CLR Via C# 读书笔记-第21章(托管堆和垃圾回收)


第 21 章 托管堆和垃圾回收

  • 应用程序受进程虚拟地址空间影响、32位进程最多分配1.5G、64位进程最多分配8TB
  • C# new一个对象,首先计算类型字段以及基类大小,然后还需要分配2个固定字段分别为类型对象指针、同步块索引32位进程以及64位进程分别会占用32位和64位
  • 引用计数法最大的问题就是循环引用问题
  • 引用跟踪法 首先跟踪法将只关心引用类型的变量称为,GC时标记所有可达对象,如果一个对象已经被标记将不会被重复标记(这样解决了引用计数的循环引用问题)、然后进行压缩(也可以说是碎片化整理)使所有被标记的对象占用内存连续(这样解决了内存碎片化问题),这样原来的所引用的对象地址还是旧的所以要加上对象在内存的偏移字节
垃圾回收和调试
大对象
  • 大对象 对象超过85000字节、不在小对象地址空间分配空间、CLR不会压缩大对象,因为移动大对象代价过高、所以会大对象之间会出现内存碎片化问题。总是被分配在第二代。
垃圾回收模式
  • 工作站模式 默认为这种情况、挂起时间短
  • 服务器模式 默认为服务器、将托管堆拆分为多个区域、分给每个CPU、每个CPU运行一个特殊线程执行回收操作
  • GC有 2种子模式 并发非并发
强制垃圾回收
  • void Collect(Int32 generation, GCCollectionMode mode, Boolean blocking); 参数分别代表回收代数、回收模式、并发或非并发
监控内存使用情况
下面代码可以在代码前后调用
Int32 CollectionCount(Int32 generation); 当前某代回收了几次
Int64 GetTotalMemory(Boolean forceFullCollection); 托管堆当前使用了多少内存
需要清理的特殊类型
  • e.g. System.IO.FileStream 类型需要打开一个文件(本机资源)并保存文件的句柄,句柄是什么?指针的指针,指针是执行对象的内存地址、但是对象会在内存变动的、所以只是知道对象的地址是可能得到错误的对象,所以使用句柄执行对象的地址,在地址发生改变时,将会更新,并且句柄的地址是不会改变的
  • GC对本机资源一无所知,当垃圾对象经历完垃圾回收后调用Finalize函数(如果重写)、对象将终结它自己,释放它包装的本机资源
  • Finalize函数函数可能会访问字段、所以可终结对象必须存活、所以被提升至下一代、并且其字段引用的对象也被提升到下一代
终结的内部工作原理
  1. 当对象被调用构造器前,如果重写了Finalize方法,将会把指向对象的指针放到终结列表
  2. 垃圾回收时,对象被标记为垃圾,然后扫描终结列表,如果在终结列表中找到,将会从列表中移除,并放入Freachable(可释放)列表中,不存在终结列表中的对象占用的内存将会被回收。CLR将会使用特殊的高优先级线程专门
  3. 对象被移到Freachable列表中,被称为对象复活了,并且对象引用的对象将会被递归复活
手动监视和控制对象的生存期
  • 原文:CLR 为每个 AppDomain 都提供了一个 GC 句柄表(GC Handle table),System.Runtime.InteropServices.GCHandle 类型在表中添加或删除记录项。
  • GCHandle中Alloc方法,会扫描句柄表查找可用记录项来存储传入的对象引用,最后返回GCHandle,其中IntPtr字段存储句柄表的索引,当调用Free方法时,IntPtr字段设为0。
  • GCHandleType具体看注释
    – Weak会在终结器调用前清零,即便对象复活,弱引用都会清除
    – WeakTrackResurrection和Weak差不多,但是如果对象复活,将不会被清除
    – Normal 透明句柄,防止被垃圾回收掉,但是会进行内存压缩
    – Pinned和Normal类似,但是不会进行内存压缩,也就是这个对象在内存中无法被移动,破坏垃圾回收效率
    //
    // 摘要:
    //     Represents the types of handles the System.Runtime.InteropServices.GCHandle class
    //     can allocate.
    public enum GCHandleType
    {
        //
        // 摘要:
        //     This handle type is used to track an object, but allow it to be collected. When
        //     an object is collected, the contents of the System.Runtime.InteropServices.GCHandle
        //     are zeroed. Weak references are zeroed before the finalizer runs, so even if
        //     the finalizer resurrects the object, the Weak reference is still zeroed.
        Weak = 0,
        //
        // 摘要:
        //     This handle type is similar to System.Runtime.InteropServices.GCHandleType.Weak,
        //     but the handle is not zeroed if the object is resurrected during finalization.
        WeakTrackResurrection = 1,
        //
        // 摘要:
        //     This handle type represents an opaque handle, meaning you cannot resolve the
        //     address of the pinned object through the handle. You can use this type to track
        //     an object and prevent its collection by the garbage collector. This enumeration
        //     member is useful when an unmanaged client holds the only reference, which is
        //     undetectable from the garbage collector, to a managed object.
        Normal = 2,
        //
        // 摘要:
        //     This handle type is similar to System.Runtime.InteropServices.GCHandleType.Normal,
        //     but allows the address of the pinned object to be taken. This prevents the garbage
        //     collector from moving the object and hence undermines the efficiency of the garbage
        //     collector. Use the System.Runtime.InteropServices.GCHandle.Free method to free
        //     the allocated handle as soon as possible.
        Pinned = 3
    }
  • 垃圾回收如何使用句柄表
    – 首先标记所有可达对象,然后扫描句柄表,将Normal、Pinned引用的对象视为标记可达(包括通过字段引用的对象)
    – 然后weak引用的对象,如果不可达(垃圾),将会把此weak引用设置为null
    – 然后扫描终结列表里面不可达对象移除,并加入到Freachable列表中(对象复活了),并标记对象,此时对象又可达了
    – 然后扫描句柄表 所有WeakTrackResurrection引用了不可达对象,将记录项引用设置为null
    – 最后进行内存压缩,Pinned项引用的对象将不会移动
  • 使用
    – C#可以使用fixed来固定代码块的对象,并且这个比Pinned类型句柄更高效
    weakWeakTrackResurrection的使用,个人理解就是间接引用:从对象A引用对象B,到对象A引用GCHanle(其中GCHandle引用真正的对象),当发生垃圾回收时,垃圾回收器会针对不同类型GCHanle做上面的操作
    WeakReference使用(短弱引用和长弱引用介绍)
    – 为了方便使用C#提供了WeakReferenceGCHandle对应关系如下
构造器调用 GCHandle 的 Alloc 方法
TryGetTarget 方法查询 GCHandle 的 Target 属性
SetTarget 方法设置 GCHandle 的 Target 属性
Finalize 方法,则调用 GCHandle 的 Free 方法
  • ConditionalWeakTable 这个用到再查

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值