C#托管堆和垃圾回收

垃圾回收

  • 值类型
    • 每次使用都有对应新的线程栈 用完自动释放
  • 引用类型
    • 全局公用一个堆 因此需要垃圾回收
  • 操作系统
    • 内存是链式分配
  • 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模式
      • 工作站模式--客户端应用程序优化
      • 服务器模式--主要优化吞吐量、资源利用
posted @ 2020-07-19 15:53  C余L小R鱼  阅读(199)  评论(0编辑  收藏  举报