堆内存碎片化-内存异常飙升,大量free对象无法释放

2,777 阅读2分钟

2023-04-04 09:25:00 服务突然异常报警,内存飙升到6g,本以为会很快恢复,结果持续不断,赶紧去打了个dump。 image.png 通过dotmrmory分析,堆存在大量的free block无法被回收释放;

image.png

问问ChatGpt:

在 .NET 中,碎片化是指在堆中存在大量零散的未使用内存块,这些未使用内存块之间存在很小的空隙,因此无法被用于分配新的对象。当碎片化严重时,堆中可能会存在大量的 free 对象,这些对象虽然已经被垃圾回收器标记为可回收对象,但由于它们的内存块太小或太分散,因此无法被用于分配新的对象。此时,这些 free 对象就会变得无法移动和使用。

free 对象无法移动的原因是,当垃圾回收器尝试移动一个对象时,它需要为该对象分配一个新的内存块,并将对象的数据复制到新的内存块中。如果堆中存在太多的零散内存块,垃圾回收器可能无法为对象分配一个连续的内存块,从而无法将对象移动到新的位置。此时,这些 free 对象就会被留在原来的位置,无法被移动。

free 对象无法使用的原因是,当程序尝试为新的对象分配内存时,垃圾回收器会查找堆中是否存在足够大的连续内存块,以容纳新的对象。如果堆中存在大量的零散内存块,那么可能会导致垃圾回收器无法找到足够大的连续内存块,从而无法为新的对象分配内存。此时,程序就会出现 OutOfMemoryException 异常,因为它无法为新的对象分配内存。

因此,当堆内存碎片化严重时,会导致大量 free 对象无法被移动和使用,从而导致垃圾回收器效率降低、内存利用率下降以及可能的 OutOfMemoryException 异常。

定位到一个业务,进行了全表查询约20w,并在内存中做计算,保守估计约2-3G左右,同时还有其他大量的业务触发,导致该对象申请到的内存可能不是连续的,导致GC时,碎片化严重;最后优化业务,避免这种全量数据内存中的操作行为;