【C# 基础】垃圾回收机制

  • 大致的组成由
    • 应用程序如何构造新对象
    • 托管堆如何控制对象的生存期
    • 如何回收对象的内存
  • CLR 要求所有对象都从托管堆分配。进程初始化时,CLR 划出一个地址空间区域作为托管堆。CLR 还要维护一个指针,我们把它称作 NextObjPtr,该指针指向下一个对象在堆中分配位置。
  • C# new 操作导致 CLR 执行步骤
    • 计算类型的字段所需要的字节数
    • 加上对象的开销所需的字节数
    • CLR 检查区域中是否有分配对象所需的字节数。如果托管堆有足够的可用空间,就在NextObjPtr 处放入对象,为对象分配的字节会被清零。接着对象的构造器,new 操作符返回对象的引用
  • 应用程序调用 new 操作符创建对象,没有足够地址来分配该对象。发现空间不够,CLR 就执行垃圾回收
    • 引用计数的坏处:对于循环引用不好处理,A 有 B 的引用,B 也有 A 的引用
    • CLR 使用引用跟踪算法,引用跟踪算法只关心引用类型的变量。
      • 值类型变量直接包含值类型实例
      • 引用类型变量可在许多场合使用(包括类的静态和实例字段,或者方法的参数和局部变量)。引用类型的变量称为根
    • GC 过程
      • 开始时,先暂停进程中所有线程
      • 进入标记阶段,CLR 遍历堆中所有对象,将同步块索引字段中的一位设为0(需要删除状态)。
      • CLR 检查所有活动根,查看它们引用了哪些对象。如果一个跟包含了 null,跳过继续检查下一个。任何根引用了堆上的对象,CLR 会检查那个对象中的根,标记它们引用的对象,如果发现已经标记,就不重新检查字段了
      • 然后 GC 的压缩阶段,CLR 使幸存的对象占用连续的内存空间
    • 一旦离开作用域,引用的对象就会 "不可达",GC 会回收内存。对象过早回收问题,注意 Timer 类的对象
      • 第 0 代:新构造的对象,垃圾回收器从未检查过。第 0 代超过预算容器会启动垃圾回收
      • 第 1 代:上一次垃圾回收中存活的对象,这时候就没有第 0 代对象了
      • 第 2 代:第 1 代占用的内存不多,只会对第 0 代进行回收。回收多次后,第 1 代占用的多了,就会对第 1 代回收,从而产生第 2 代
      • 没有第 3 代 0.0
    • 垃圾回收触发条件
      • 显示调用 System.GC 的 Collect 方法(强制垃圾回收,微软爸爸很反对这种请求)
      • 报告低内存时
      • CLR 正在卸载 AppDomain
      • CLR 正在关闭
    • 大小对象
      • 目前说的对象都是小对象。大对象 >= 85000 b
      • 大对象不在小对象地址分配
      • GC 不压缩大对象
      • 大对象总是第 2 代,只能为需要长时间存活的资源创建大对象。频繁的话性能太差了
    • 需要特殊清除的类型
      • 本机资源的类型被 GC 时, GC 会回收对象在托管堆中使用的内存。但这样会造成本机资源的泄漏。CLR 提供了称为终结的机制。CLR 判定一个对象不可达时,对象将终结它自己,释放它包装的本机资源。随后 GC 回收内存
      • System.Object 定义了受保护的虚方法 Finalize,垃圾回收器判定对象是垃圾后,会调用(如果重写)。
      • 但是 Finalize 问题很多
        • 首先要延长生存时间,提升代等级
        • 执行时间无法控制,调用顺序无法保证
        • 这是为释放本机资源设计的,不要重写 Object 的 Finalize!!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值