.Net CLR 内存模型小结

.Net CLR的内存模型和JVM的内存模型有很多相似的地方。《JVM 结构小结》

 

 1 进程内存空间

应用程序的内存受进程的虚拟地址空间的限制。

  • 32位进程:最多1.5GB
  • 64位进程:最多8TB

2 引用跟踪算法

为了解决“引用计数算法”中处理不好循环引用的问题,CLR采用了引用跟踪算法,只关心引用类型的变量——根。值类型变量直接包含实例,变量销毁,整个实例也销毁了。

3 GC过程

3.1 暂停线程

暂停进程中所有线程,防止它们在GC期间更改对象状态。

3.2 标记阶段

  1. 遍历堆中所有对象,并将同步块索引字段中的一位设为0。即假定所有对象都不可达,都是垃圾。
  2. 遍历所有(栈中的)活动根,将其引用对象的同步块索引中的位设为1,表示可达,需要保留。
  3. 检查上一步可达对象中的根,标记其引用的对象为可达。对可达对象重复执行该步骤,直到所有根都检查完毕。



 

3.3 压缩阶段

将需要保留的对象移到一起。更新每个根中引用对象的地址(即减去对象在内存中偏移的字节数)。

4 代

类似JVM内存管理中的新生代和老年代概念,.Net CLR的中也有“代”的概念。

  • CLR在分配新对象时,如果所需内存超出预算,马上执行一次GC。
  • 为了加快速度,只回收 0代 对象,忽略 1代 中的不可达对象。幸存下的 0代 对象提升为 1代。
  • 如果发现 1代 的内存占比过高,会回收 0代 和 1代 中所有不可达对象。幸存的 1代 升为 2代(最高代),0代 升为 1代。
  • 如果没有回收到足够内存,CLR会做一次完整GC。如果还是不够,就抛异常 OutOfMemoryException。
  • CLR会在GC过程中了解应用程序的行为,从而动态调节各代对象内存占比的预算。

5 大对象

(目前)85000字节及以上的对象被认为大对象。因为在内存中移动它的代价太高,GC一般不压缩大对象。大对象被归为 2代对象。常见的有大字符串和I/O字节数组等。

6 GC模式

6.1 工作站模式

为避免用户感到焦虑,GC被优化成低延时。

6.2 服务器模式

为提升吞吐量和资源利用率,(假定)机器的所有CPU都可用于辅助GC。托管堆被拆分为“一个CPU,一块内存区域”,每个CPU上都运行一个特殊线程,它们并发回收各自区域。

可通过配置文件启用服务器模式。

<configuration>
  <runtime>
    <gcServer enabled="true" />
  </runtime>
</configuration>

 

7 手动监视和控制对象的生存期

每个AppDomain一个GC句柄表,表中每一项包含堆中一个对象的引用和如何监控对象的标志(flag)。

为简化操作,用WeakReference<T>来替代GCHandle。

猜你喜欢

转载自pre.iteye.com/blog/2365891
CLR
今日推荐