六安人社局网站,林州做网站,推荐网站建设,房地产开发建设网站第二十一章 托管堆和垃圾回收
内存分配过程 CLR维护一个“下一次分配指针”#xff08;NextObjPtr#xff09;#xff0c;指向当前托管堆中第一个可用的内存地址 计算类型所需的字节数#xff0c;加上对象开销#xff08;类型对象指针、同步块索引#xff09;所需字节数…第二十一章 托管堆和垃圾回收
内存分配过程 CLR维护一个“下一次分配指针”NextObjPtr指向当前托管堆中第一个可用的内存地址 计算类型所需的字节数加上对象开销类型对象指针、同步块索引所需字节数检查空间是否足够如果空间足够更新指针到分配的对象末尾如果空间不足触发垃圾回收释放未使用内存 垃圾回收算法 把引用类型变量称为根标记暂停所有线程遍历堆中所有对象在同步块索引上标记为应该删除不可达如果任何根引用了堆上的对象则标记为可达压缩移动幸存的对象使它们占用连续的空间类似碎片整理同时更新被移动对象的地址移动NextObjPtr指向最后一个幸存对象之后的位置如果回收不了内存说明内存已耗尽抛出异常 静态字段引用的对象一直存在可能会使其引用的对象一直存活造成内存泄漏分代回收算法原理新分配的对象生存周期短老对象生存周期长 新创建的对象称为第0代对象CLR初始化时为第0代选择一个预算容量当容量不足时触发垃圾回收幸存的对象就是第1代如果根或对象引用了老一代的某个对象那么可以忽略老对象内部的所有引用如果老对象引用了新对象设置了其他机制标记如果第1代也用完预算则变为第2代同时第0代变为第1代最高就是第2代没有第3代预算大小是CLR根据每次回收垃圾的多少来动态决定的启发式算法如果第0代所有对象都是垃圾可以通过将NextObjPtr移到起始处直接完成垃圾回收 垃圾回收触发条件 代码显式调用Collect方法回收不推荐windows报告内存低CLR卸载AppDomain 执行所有代的回收CLR关闭 进程终止由windows回收进程全部内存 大对象 大于85KB的大对象专门分配在大对象堆GC不会压缩大对象大对象总是第2代垃圾回收模式 工作站模式针对单用户环境优化单线程垃圾回收低延迟优先服务器模式针对多用户优化多线程垃圾回收堆空间更大暂停时间较长 应尽量避免使用Finalize这个方法在GC结束后调用由于该方法中可能使用到对象的字段导致对象在回收时延长了存活时间Finalize方法的执行时间和顺序是不可控制的Finalize方法在专用的线程上执行一旦阻塞则无法调用其他Finalize方法造成内存一直泄露封装本机资源时推荐从SafeHandle类派生以保证本机资源在垃圾回收时释放IDisposable接口 如果类定义的一个字段实现了dispose模式那么类本身也应该实现dispose模式对象被显式dispose后对象本身依然存在using语句初始化对象编译器会自动生成try-finally块并在finally中调用Dispose方法 StreamWriter包装了一个Stream(FileStream或MemoryStream)如果没有显式调用Dispose会造成缓冲区丢失StreamWriter不支持终结就算支持如果Stream先终结StreamWriter也无法正确终结本机资源可能占用大量内存而占用很小的托管内存为使GC能正确感知内存压力及时执行垃圾回收可以使用AddMemoryPressure、RemoveMemoryPressure来修正Finalize的原理维护一个终结列表和F-Reachable队列当对象的实例构造器被调用前如果定义了Finalize方法则加入终结列表被当可终结对象被回收时离开终结列表进入freachable 队列(此时对象又有引用了(被这个队列引用)不再是垃圾)然后由专用线程调用队列中对象的Finalize方法调用完成后对象可能被提升到较老的一代然后等待下次被回收此时已经不在终结列表中了这次会被正常回收。GCHandle类提供了对托管对象的直接控制避免垃圾回收器意外回收对象 标志位GCHanleType定义 Weak弱引用此类型的句柄不会阻止垃圾回收器回收对象。如果对象被垃圾回收句柄会指向 null回收后不可访问无法恢复WeakTrackResurrection弱引用但Finalize调用后仍然可达在终结器完成之前句柄仍有效Normal普通句柄对象在使用该类型的句柄时不会被垃圾回收必须手动释放句柄Pinned固定句柄对象固定在内存中垃圾回收器不能移动它 弱引用当对象只通过弱引用被引用时垃圾回收器会认为该对象是不可达的从而可以对其进行回收 用GCHandle创建一个对象的弱引用(Weak)当GCHandle.Target返回null时表示对象已经被回收 用GCHandle创建一个对象的Normal引用然后将此对象传给非托管代码非托管代码就可以使用GCHandle.Target来获取托管对象的指针这能保证托管对象一直存活、在内存中移动也不丢失如果已用完需用Free方法释放 用GCHandle创建一个对象的Pinned引用然后用GCHandle.AddrOfPinnedObject获得已固定对象的指针保证该地址中的数据在内存中不会移动 fixed语句可以直接在unsafe代码块中临时固定对象 ConditionalWeakTable实现了对Key是弱引用但只要key未被回收value一定未被回收