CLR 垃圾回收
2019-01-06 21:54:03 0 举报
AI智能生成
CLR 垃圾回收梳理
作者其他创作
大纲/内容
手动管理内存容易出现的Bug
未释放内存导致内存泄漏
<div>引用已释放的内存</div>
<div>托管堆创建对象的过程<br></div>
CLR维护指针NextObjPtr,指向下一个对象分配空间的地址
<div>new 操作符的过程</div>
计算类型所需字节
加上两个对象开销字节
类型对象指针
<div>同步块索引(用来GC)</div>
CLR检查托管堆剩余空间,如果有足够空间就在NextObjPtr所指向的地址处放入对象
<div>将NextObjPtr指向下一个对象放入的地址<br></div>
<div>new 操作符返回对象引用</div>
<div>垃圾回收算法</div>
引用计数算法
过程
每个对象都维护一个内存来统计有多少“部分”正在使用对象,当计数为0时进行垃圾回收
缺点
当出现循环引用时,计数将永远不会为0
<div>引用追踪法</div>
只关心引用类型的变量,因为值类型的变量直接包含值类型的实例
<div>引用类型的变量称为根</div>
<div>过程</div>
GC开始时,暂停所有线程
遍历托管堆中所有的对象,并将同步索引块中的一位设为0
<div>检查所有的活动根,查看他们引用那些对象,并将这些对象同步索引块中的一位设为1</div>
<div>如果根包含null,及未引用任何对象,则忽略这个根,继续检查下一个,直到检查完毕</div>
对标记为0的对象(不可达)进行垃圾回收,标记为1的对象(可达)不回收
<div>进入GC压缩阶段,对标记为1的对象进行压缩,使他们占用连续的内存空间</div>
<div>CLR对每个根减去所引用对象在内存中偏移的字节数,以保证每个根还是引用之前的对象</div>
<div>将NextObjPtr指向最后一个幸存对象之后的位置</div>
<div>如果内存已满,则在使用new开辟新的内存空间时会引发OutOfMemoryException</div>
优点
解决循环引用问题
<div>GC压缩后,使对象仍占用连续的内存空间,解决堆空间的内存碎片化问题,减小应用程序工作集,提高性能</div>
<div>开发中注意事项</div>
尽量避免使用静态字段
<div>原因</div>
静态字段引用会一直存在,直到用于加载类型的AppDomain被卸载为止
当静态字段引用一个集合对象,并不断的向集合对象中加入数据,则会引发内存溢出
使用“代”提升性能
几点假设
对象越新,生存期越短
<div>对象越老,生存期越长</div>
回收堆的一部分,速度快于回收整个堆
<div>每一代都会都会有一个预算容量,如果超过这个预算容量就要对这一代对象进行一次垃圾回收</div>
<div>GC托管堆只支持3代对象</div>
第0代对象
新构造的对象,垃圾回收器从未检查它们
<div>当超过预算,则会对第0代对象进行压缩回收,幸存对象称为第1代对象</div>
在垃圾回收时要检查老对象的引用更新
利用JIT编译器内部机制,当对象引用发生变化时,会设置一个位标志
<div>垃圾回收器就知道哪些老对象的引用已写入</div>
<div>对字段发生变化的老对象进行检查是否引用了任何第0代的任何新对象</div>
<div>第1代对象</div>
在0代对象回收中存活的对象称为第1代对象,它们经历过一次垃圾回收器的检查
<div>当对第0代对象进行压缩而超过第1代对象预算时,则对第1代进行压缩回收,幸存对象称为第2代对象</div>
第2代对象
在1代对象回收中存活的对象称为第2代对象,它们经历过二次垃圾回收器的检查
当没有回收到足够的内存时,GC会执行一次完整回收,还不够就是引发OutOfMemoryException
<div>垃圾回收触发条件</div>
<div>非强制回收</div>
当第0代对象超出预算时
CLR正在卸载AppDomain
<div>CLR在正常终止时关闭</div>
强制回收
代码显示调用System.GC的静态Collect方法
<div>Windows报告低内存情况</div>
<div>垃圾回收模式<br></div>
主要模式
工作站模式
针对客户端应用程序优化的GC
<div>降低GC造成的延迟</div>
<div>服务器模式</div>
并发回收
<div>被优化的主要时吞吐量和资源利用</div>
子模式
并发模式
GC会有一个额外的线程,在程序运行时并发标记对象,查找不可达对象。当GC开始时,不需要再进行标记,可直接进行压缩,减少GC时间
<div>使用并发模式,应用程序消耗的内存比非并发的多</div>
<div>非并发模式</div>
收藏
收藏
0 条评论
下一页