一 、创建对象及生命周期
要使用这些资源,必须为代表资源的类型分配内存,进程初始化时,CLR划出一个地址区域作为托管堆,NextObjPtr指针指向下一个对象在托管堆中的分配位置,步骤如下:
1.new一个对象,调用IL指令newobject,为对象分配内存
- 对象大小估算:计算对象的字段所需的字节数,加上对象开销所需的字节数(类型对象指针,同步块索引)
- 检查托管堆内存:
- 内存充足,在NextObjptr指针指向的地址放入对象,为构造器的this参数传递内存地址
- 内存不足,触发CG回收
2.初始化内存,实例构造器设置初始状态
3.使用资源
4.清理资源
5.释放内存(GC垃圾回收)
创建一个新对象的流程
二、GC垃圾回收
1 引用跟踪算法:判断对象是否属于垃圾
2 垃圾回收的基本流程:
- 标记:暂停进程中所有线程,CLR遍历堆中所有对象,将同步块索引字段标记为0(不可达对象),检查所有活动根,如果根引用了对象,标记该对象的同步块索引为1(可达对象)。
- 清除:清除所有不可达对象
- 压缩:碎片整理,把剩下的对象转移到一个连续的内存,把root和指针的地址修改为移动后的地址
3 垃圾回收触发条件:
- 内存不足时(0代对象已满)
- 显示调用System.GC
- windows报告内存不足,CLR强制垃圾回收释放死对象
- CLR正在卸载appDomain
- CLR正在关闭
三、关于代龄
CLR的GC是居于代的垃圾回收器,分代回收速度快于回收整个堆。
分代算法的假设条件:
- 对象越新,生存期越短
- 对象越老,生存期越长
- 回收堆的一部分,速度快于回收整个堆
- 新创建的对象之间关联度较高
三个 代龄区域:
- 0代:新添加到堆的对象,垃圾回收从未发生过
- 1代:0代满了,会触发垃圾回收,0代垃圾回收后,剩下的对象会被搬到1代
- 2代:当0代 1代满了,会触发0代 1代的垃圾回收,第0代升为1代,第1代升为2代
大对象:
- 大于等于85000字节的对象成为大对象
- 大对象不在小对象的地址空间分配,而在进程地址空间的其他地方分配
- 大对象总是第2代,所以需要长时间存活的资源创建大对象
四、非托管资源回收
通过Finalize()和Dispose()。
Finalize():
Dispose():
参考
- 《CLR Via c#》第4版
- .NET面试题解析06-GC与垃圾回收