垃圾回收
- 值类型
- 每次使用都有对应新的线程栈 用完自动释放
- 引用类型
- 全局公用一个堆 因此需要垃圾回收
- 操作系统
- 内存是链式分配
- CLR
- 内存连续分配(数组) 要求所有对象从 托管堆分配
- GC
- 触发条件
- New对象时 计算是否有足够的空间来分配该对象 若空间不足 则CLR就执行GC
- 显示调用Collect 强制回收
- Windows报告内存过低
- CLR 卸载AppDomain时 CLR认为不存在根 开始对所有代进行GC
- CLR正在关闭 进程要终止了
- 垃圾回收算法-- 引用跟踪算法
- 该算法只关心引用变量--因为引用变量才能引用堆上对象、值类型直接包含类型实例
- 所有引用类型变量都称为-- 根
- GC过程
- 暂停进程中所有线程
- CLR进入GC标记阶段 遍历堆中所有对象 将同步块索引字段中的位设为0(表明所有对象都应删除)
- 检查所有活动根 查看根所引用的对象 所有被引用对象的同步块索引字段中的位设为1 进行标记(对象被标记后 CLR会检查被标记对象中的根 并标记它们引用的对象 如果一个对象已被标记 则不重新检查该对象 避免死循环) 【已标记对象-- 可达对象 反之 不可达对象 】
- GC开始压缩--删除不可达对象 并将可达对象 移动至一块连续的内存空间 【内存连续 实现了引用的 局部化 减少了程序的工作集 提高了访问性能】
- GC常见BUG
- OutOfMemoryException--若CLR在GC后没有回收到足够内存 无法对新对象进行分配 便会抛此异常(其中静态字段引用对象 会一直存在知道AppDomain卸载为止 所以让静态字段引用某个集合对象 然后不停的向集合添加数据 常常是内存泄漏的原因之一)
- 引用对象 t=null 并不会实现对象的回收 因为JIT编译器是一个优化编译器 对于将局部变量或参数设为null时 JIT会将t=null 整行代码优化掉
- 性能提升--基于代的垃圾回收器
- 只支持3代 0代 1代 2代 经历一次GC 代会提升一次 0代总是最新的对象 2代是最老的对象 很少回收2代变量 CLR初始化时 会为每一代选择预算内存大小
- 垃圾回收器每次会根据引用 构建 可达对象图 再根据可达对象图 进行回收 提高性能
- CLR的垃圾回收器是自调节的 会自动根据程序需求调节代的内存分配
- GC模式
- 工作站模式--客户端应用程序优化
- 服务器模式--主要优化吞吐量、资源利用
- 触发条件