.net性能调优-垃圾回收!!!最全垃圾回收来了(代码片段)

Java架构没有996 Java架构没有996     2022-12-25     468

关键词:

目前项目开发基本都基于.NetCore 3.1以上了,有些老版本的规则和概念也没有列出来,低版本的垃圾回收类型和内存释放方式会有所不同

垃圾回收器为什么存在

  • 开发人员不必手动释放内存。

  • 有效分配托管堆上的对象。

  • 回收不再使用的对象,清除它们的内存,并保留内存以用于将来分配。 托管对象会自动获取干净的内容来开始,因此,它们的构造函数不必对每个数据字段进行初始化。

  • 通过确保对象不能使用另一个对象的内容来提供内存安全。

托管堆代数

概述

为优化垃圾回收器的性能,将托管堆分为三代:第 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来代替Task,Task为引用类型,cpu密集型的调用会频繁触发第0代的GC回收
  • 尽可能重复使用HttpClient
  • 使用ArrayPoolMemoryPool从缓冲池中租用对象空间
  • 使用弱引用WeakReference重复使用已不再使用但尚未被回收的对象

监控及调试

  • 监听垃圾回收 ETW 事件,可用PerfView查看ETW事件,适用于window平台。也可在代码中引入Microsoft.Diagnostics.Tracing.TraceEventnuget包在代码中监听指定的GC回收等事件自定义后续处理逻辑

  • 使用性能监视器Perfmon.exe,适用于windows平台

  • 使用SOS调试,抓取dump转储文件后用WinDbg进行分析诊断,适用范围较广,可看到最全的内存信息

  • .Net CLI工具dotnet-counters,可以看到大概的性能指标数据统计结果,适用于临时运行状况查看和监视

.net性能调优-垃圾回收!!!最全垃圾回收来了(代码片段)

...容来提供内存安全。托管堆代数概述为优化垃圾回收器的性能,将托管堆分为三代:第0代、第1代和第2代。目的是为了单独处理短生存期对象和长生存期对象。垃圾回收器大部分时间都在处理短生存期对象的回收。底层... 查看详情

spark性能优化-jvm虚拟机垃圾回收调优

12 34 查看详情

day799.优化垃圾回收机制-java性能调优实战(代码片段)

...不少工作量。但完全交由JVM回收对象,也会增加回收性能的不确定性。在一些特殊的业务场景下,不合适的垃圾回收算法以及策略,都有可能导致系统性能下降 查看详情

记录一次es的性能调优(代码片段)

文章目录es性能调优启用g1垃圾回收器es性能调优成都的es集群经常出现告警,查看日志发现[gc][11534155]overhead,spent[38.3s]collectinginthelast[38.6s]这是JVM垃圾回收过程中的一条日志,表示在最近38.6秒内,JVM进行了一次GC(GarbageC... 查看详情

jvm技术专题性能调优之cms垃圾回收器「下篇」(代码片段)

...查看这篇文章,希望先去看一下上部【JVM技术专题】性能调优之CMS垃圾回收器「上篇」,本文承接上文内容,进行深入分析CMS原理以及调优和相关问题的分析等。学习背景关于CMSGC介绍和调优的文章比较多,但大... 查看详情

jvm调优总结-反思

...确实带来了很多好处,为开发带来了便利。但是在一些高性能、高并发的情况下,垃圾回收确成为了制约Java应用的瓶颈。目前JDK的垃圾回收算法,始终无法解决垃圾回收时的暂停问题,因为这个暂停严重影响了程序的相应时间... 查看详情

(超详解)jvm-垃圾回收(代码片段)

...收器4-1串行4-2吞吐量优先4-3响应时间优先4-4G15.垃圾回收调优5-1调优领域5-2确定目标5-3最快的GC5-4新生代调优5-5老年代调优JVM-垃圾回收本文章参考:黑 查看详情

jvm技术专题性能调优之cms垃圾回收器「上篇」(代码片段)

前提概要如果没有冬天,春天不会如此悦人;如果没有偶尔的不幸,幸运不会如此受人欢迎。CMS垃圾回收的6个重要阶段initial-mark初始标记(CMS的第一个STW阶段),标记GCRoot直接引用的对象,GCRoot直接引... 查看详情

jvm垃圾回收算法(最全)

JVM垃圾回收算法(最全) 下面是JVM虚拟机运行时的内存模型: 1.方法区Perm(永久代、非堆)2.虚拟机栈3.本地方法栈(Native方法)4.堆5.程序计数器 1首先的问题是:jvm如何知道那些对象需要回收?目前两种标识算法、... 查看详情

jvm调优垃圾回收算法

原文出处: pengjiaheng可以从不同的的角度去划分垃圾回收算法:按照基本回收策略分引用计数(ReferenceCounting):比较古老的回收算法。原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃圾回收时... 查看详情

jvm调优垃圾回收算法

可以从不同的的角度去划分垃圾回收算法:按照基本回收策略分引用计数(ReferenceCounting):比较古老的回收算法。原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃圾回收时,只用收集计数为0的对... 查看详情

jvm性能调优之垃圾回收算法

一、标记清除算法     标记清除算法顾名思义,就是将需要回收的对象进行标记,然后进行清除。那么这个算法就有标记和清除两种过程。标记过程主要是通过可达性分析算法进行判断存活对象,然后遍历所有... 查看详情

jvm调优总结-垃圾回收面临的问题

如何区分垃圾   上面说到的“引用计数”法,通过统计控制生成对象和删除对象时的引用数来判断。垃圾回收程序收集计数为0的对象即可。但是这种方法无法解决循环引用。所以,后来实现的垃圾判断算法中,... 查看详情

jvm调优

...除(复制)算法:Serial算法(单线程)并行算法并发算法性能调优对程序及JVM进行调优。从以下几个方面进行:线程池:解决用户响应时间长的问题连接池JVM启动参数:调整各代的内存比例和垃圾 查看详情

jvm调优(3)垃圾回收面临的问题

原文出处: pengjiaheng如何区分垃圾上面说到的“引用计数”法,通过统计控制生成对象和删除对象时的引用数来判断。垃圾回收程序收集计数为0的对象即可。但是这种方法无法解决循环引用。所以,后来实现的垃圾判断算法... 查看详情

jvm调优新一代的垃圾回收算法

原文出处: pengjiaheng垃圾回收的瓶颈传统分代垃圾回收方式,已经在一定程度上把垃圾回收给应用带来的负担降到了最小,把应用的吞吐量推到了一个极限。但是他无法解决的一个问题,就是FullGC所带来的应用暂停。在一些... 查看详情

jvm调优相关

 1、串行垃圾收集器线程:单线程,无需线程交互,效率高;适用于单核处理器,或者小数据量(100M)情况下;-XX:UseSerialGC:打开串行收集器2、并行垃圾收集器线程:多线程,减少垃圾回收时间,适用于多核处理器;  -XX:U... 查看详情

性能调优之jvm调优gc性能指标及调优实战

...JVM运行环境解决JVM运行中出现的各种问题,比如OOMGC性能指标吞吐量:工作线程运行时间占比总运行时间之比用户程序执行时间/(用户程序执行时间+垃圾回收时间)单位时间内,STW的时间最短(发生2次STW... 查看详情