大连做网站绍兴厂商,商城网站数据库表关系设计,福州做网站外包,wordpress怎样搭建网站目前项目开发基本都基于.NetCore 3.1以上了#xff0c;有些老版本的规则和概念也没有列出来,低版本的垃圾回收类型和内存释放方式会有所不同
垃圾回收器为什么存在 开发人员不必手动释放内存。 有效分配托管堆上的对象。 回收不再使用的对象#xff0c;清除它们的内存有些老版本的规则和概念也没有列出来,低版本的垃圾回收类型和内存释放方式会有所不同
垃圾回收器为什么存在 开发人员不必手动释放内存。 有效分配托管堆上的对象。 回收不再使用的对象清除它们的内存并保留内存以用于将来分配。 托管对象会自动获取干净的内容来开始因此它们的构造函数不必对每个数据字段进行初始化。 通过确保对象不能使用另一个对象的内容来提供内存安全。
托管堆代数
概述
为优化垃圾回收器的性能将托管堆分为三代第 0 代、第 1 代和第 2 代。目的是为了单独处理短生存期对象和长生存期对象。垃圾回收器大部分时间都在处理短生存期对象的回收。
底层一代的GC回收会触发年轻一代的GC回收第二代的GC回收会触发完整的GC回收.
第0代暂时代第1代暂时代第2代LOH逻辑第3代所处内存段暂时段暂时段非暂时段非暂时段
LOH大型对象堆实际位于第二代 单独在第二代上为其划分了一块区域。 逻辑上称为第3代 | | 包含 | 短生存期对象即新分配的对象 | 短生存期对象从第0代回收后 未被回收的对象升级为第1代。 | 长生存期的对象第一代回收后 未被回收的对象升级为第2代。 | 对象的大小 85,000 字节 | | 回收条件 | 第0代已分配内存达到阈值 如果第0代已满仍尝试创建新对象 调用GC.Collect()方法 第1代GC回收 | 第1代已分配内存达到阈值 第0代回收之后仍然没有足够的空间存放新对象此时会先回收第1代再回收第2代 调用GC.Collect方法 第2代GC回收 | 第2代已分配内存达到阈值 第0代回收之后仍然没有足够的空间存放新对象此时会先回收第1代再回收第2代 调用GC.Collect方法 达到LOH回收条件 系统内存不足 | 达到第2代回收条件 大型对象内存分配达到阈值 | | 回收方式 | 前台垃圾回收当前托管线程被挂起 | 前台垃圾回收当前托管线程被挂起 | 后台垃圾回收当前托管线程正常执行 | 同第二代 | | | | | | |
想要判断一个对象是否为大对象可通过以下代码查看
var o new Byte[85000];
Console.WriteLine(GC.GetGeneration(o));//GC2,大对象
o new Byte[84900];
Console.WriteLine(GC.GetGeneration(o)); //GC0小对象 84999仍是大对象需要用一定量的内存空间保存指针
var arr new int[85000 / 4];
Console.WriteLine(GC.GetGeneration(arr));//GC2,大对象数组会提前开辟空间, int占32位4个字节,85000 / 4加上指针内容会达到大对象的大小
arr new int[85000 / 4 - 20];
Console.WriteLine(GC.GetGeneration(arr));//GC0,小对象
阈值
当垃圾回收器检测到某个代中的幸存率很高时它会增加该代的分配阈值避免垃圾回收过于频繁地运行
但是阈值调大之后会导致一次回收的内存过高。
所以阈值由CLR动态决定以调节 回收频率和单次回收内存大小的平衡
垃圾回收类型
工作站默认方式服务器特点垃圾回收线程同用户线程优先级相同会与用户线程争用CPU资源只有一个处理器的计算机无论是否修改配置文件最终都会应用工作站垃圾回收方式有垃圾回收的专用线程
线程优先级为THREAD_PRIORITY_HIGHEST 每个CPU都会分配一个垃圾回收专用线程和专用堆。不同的堆可以互通 多个垃圾回收线程一起工作所以堆大小相同时服务器垃圾回收比工作站垃圾回收快 | | 适用场景 | 普通场景 | 需要高吞吐量和可伸缩性的服务器应用程序 |
内存释放
释放目标
GC释放应用程序不再使用的对象的内存通过检查应用程序的根来确定不再使用的对象应用程序的根包括静态字段、局部变量、CPU 寄存器、GC 句柄和终结队列
释放步骤
- 列出不可访问对象和幸存对象的地址块并**标记**
- 使用内存复制功能压缩可以访问的对象到不可访问的地址块中,就是把存活下来的对象重新排列到连续的内存块中
- 大对象通常不会压缩因为大对象所占用的内存区域过大移动成本太大
- 回收死空间
- 指针更正让对象指针指向新地址指针更正是因为压缩了对象对象在内存中的位置发生了变化
代码调优
始终调用引用对象的Dispose方法始终在实现了IDisposable的类中正确实现析构函数静态类中分配的对象不再使用后及时删除禁止在IOC声明为单例生命周期的类中注入瞬时生命周期的对象非必要时不要创建大型对象可视情况用ValueTask来代替TaskTask为引用类型cpu密集型的调用会频繁触发第0代的GC回收尽可能重复使用HttpClient使用ArrayPool或MemoryPool从缓冲池中租用对象空间使用弱引用WeakReference重复使用已不再使用但尚未被回收的对象
监控及调试 监听垃圾回收 ETW 事件,可用PerfView查看ETW事件适用于window平台。也可在代码中引入Microsoft.Diagnostics.Tracing.TraceEventnuget包在代码中监听指定的GC回收等事件自定义后续处理逻辑 使用性能监视器Perfmon.exe,适用于windows平台 使用SOS调试,抓取dump转储文件后用WinDbg进行分析诊断适用范围较广可看到最全的内存信息 .Net CLI工具dotnet-counters,可以看到大概的性能指标数据统计结果适用于临时运行状况查看和监视