.Net CLR的内存模型和JVM的内存模型有很多相似的地方。

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

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

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

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

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

    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上都运行一个特殊线程,它们并发回收各自区域。

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






    7 手动监视和控制对象的生存期
    每个AppDomain一个GC句柄表,表中每一项包含堆中一个对象的引用和如何监控对象的标志(flag)。

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

    ————————————————
    版权声明:本文为CSDN博主「一个被IT搞的」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/hchaoh/article/details/69390914