• CLR via C# 笔记 -- 托管堆和垃圾回收(21)


    1. 访问一个资源所需的步骤

      1). 调用IL指令newobj,为代表资源的类型分配内存(一般使用C# new 操作符来完成)。

      2). 初始化内存,设置资源的初始状态并使资源可用。类型的实例构造器负责设置初始状态。

      3). 访问类型的成员来使用资源(有必要可以重复)。

      4). 摧毁资源的状态以进行清理。

      5). 释放内存。垃圾回收器独自负责这一步。

    分配并初始化资源并直接使用。大多数类型都无需资源清理,垃圾回收器会自动释放内存。

    2. 从托管堆分配资源

     CLR 要求所有对象都从托管堆分配。进程初始化时,CLR划出一个地址空间区域作为托管堆。CLR还要维护一个指针,我把它称作NextObjPtr。该指针指向下一个对象在堆中的分配位置。

     一个区域被非垃圾对象填满后,CLR会分配更多区域。这个过程一直重复,直到整个进程地址空间被填满。所以,你的应用程序的内存受进程的虚拟地址空间的限制。32位进程最多能分配1.5GB,64位进程最多能分配8T。

    3. new操作符导致CLR执行以下步骤

      1). 计算类型的字段(以及从基类型继承的字段)所需的字节数

      2). 加上对象的开销所需的字节数。每个对象都有两个开销字段:类型对象指针和同步块索引。对于32位应用程序,这两个字段各自需要32位,所以每个对象要增加8个字节。对于64位应用程序,这两个字段各自需要64位,所以每个对象要增加16个字节。

      3). CLR检查区域中是否有分配对象所需的字节数。如果托管堆有足够的可用空间,就在NextObjPtr指针指向的地址处放入对象,为对象分配的字节会被清理。接着调用类型的构造器(为this参数传递NextObjPrt),new操作符返回对象引用。就在返回这个引用之前,NextObjPrt指针的值会加上对象占用的字节数得到一个新值,即下个对象放入托管堆时的地址。

    4. 垃圾回收算法。应用程序调用new操作符创建对象时,如果第0代没有只够的地址空间来分配对象,CLR就执行垃圾回收。

    引用追踪法:CLR开始GC时,首先暂停进程中的所有线程。这样可以防止线程在CLR检查期间访问对象并更改其状态。然后,CLR进入GC的标记阶段。在这个阶段,CLR便利堆中的所有对象,将同步块索引字段中的一位设为0,这表明所有对象都应删除。然后,CLR检查所有活动的根,查看它们引用了哪些对象。如果根引用了堆上对象,则将同步块索引字段中的一位设为1。检查完毕后,未标记的会被删除,已标记的会被转移,并从每个根减去所引用的对象的内存中偏移的字节数。

    静态字段应用一直存在,直到用于加载类型的AppDomain卸载为止(考虑内存泄漏)。

    5. GC是基于代的垃圾回收器。共有第0代,第1代和第2代。第0代对象就是那些新构造的对象。CLR初始化时为第0代对象选择一个预算容量(以KB为单位)。如果分配一个新对象造成第0代超过预算,就启用一次垃圾回收,垃圾回收中存活的对象现在成为第1代,第0代不再包含任何对象。第2代同理。预算是根据回收量动态调节的

    6. 触发GC的条件

      1). 第0代超预算时

      2). 显示调用GC.Collect方法

      3). window报告低内存情况,通过 CreateMemoryResourceNotification 和 QueryMemoryResourceNotification监视系统总体内存使用情况

      4). AppDomain卸载时

    7. 大对象。超过85000字节或更大的对象。

      1). 大对象不是在小对象的地址空间分配,而是在进程地址空间的其他地方分配的。

      2). 目前版本GC不压缩大对象,可能会造成碎片化。

      3). 大对象总是2代。不可能是 1代或0代。只能为长时间存活的资源创建大对象。

    8. GC模式

      1). 工作站:默认值;该模式针对客户端应用程序优化GC。GC造成的延时成本很低,应用程序线程挂起时间很短,避免使用户感到焦虑。

      2). 服务器:该模式针对服务器端应用程序优化GC。被优化的主要是吞吐量和资源利用。GC假定机器上没有运行其他应用程序,并假定机器的所有CPU都可用来辅助完成GC。该模式造成托管堆被拆分成几个区域,每个CPU一个。开始垃圾回收时,垃圾回收器在每个CPU上都运行一个特殊线程;每个线程都和其他线程并发回收它自己的区域。对于工作者线程(worker thread)行为一致的服务器应用程序,并发回收能很好的进行。

    9. Finaliize 方法。被视为垃圾的对象在垃圾回收完毕后才调用Finalize方法,所以这些对象的内存不是马上被回收,因为Finalize方法可能要执行访问字段的代码。可终结对象在回收时必须存活,造成它被提升到另一代,使对象活的时间比正常的长。

  • 相关阅读:
    约数个数 和 约数之和
    二分模板
    新生赛补题
    codefores刷题心得3 思维+dp(特别好玩)
    二叉树的遍历及例题
    团队作业七——团队作业分配
    WarPlane——游戏设计文档
    团队作业(五)
    团队作业(四)
    团队项目方案分析
  • 原文地址:https://www.cnblogs.com/Cxiaoao/p/14846527.html
Copyright © 2020-2023  润新知