G1垃圾回收器中,内存被分成1M左右大小,那么当来一个很大的对象,如32M该怎么存放?

你好,我是风一样的树懒,一个工作十多年的后端开发,曾就职京东、阿里等多家互联网头部企业。

点击下方👇关注公众号,带你一起复习后端技术,看看面试考点,补充积累技术知识,每天都为面试准备积累

在 G1 垃圾回收器(Garbage First, G1 GC)中,堆内存被划分为大小相等的多个区域(Region),每个 Region 的大小通常为 1MB,但可以根据堆的大小自动调整,一般范围是 1MB 到 32MB。G1 使用 Region 作为最小的内存管理单位,来支持更灵活的内存分配。

当遇到一个很大的对象(如 32MB)时,G1 GC 有专门的处理方式,这类对象称为 大对象(Humongous Object):


01
什么是 Humongous Object?


G1 GC 中,凡是大于等于 Region 大小的一半 的对象都会被认为是大对象。

比如,Region 大小为 1MB,则所有大于等于 512KB 的对象都被视为 Humongous Object。


02
存放方式


对于 Humongous Object,G1 并不会直接将它分散存储在多个普通的 Region 中,而是采用以下策略:

专用的 Humongous Region:

  • 大对象会被存储在一组连续的 Region 中。

  • 第一个存储大对象的 Region 被标记为 Humongous Region。

  • 后续需要的 Region 也会被分配并标记为 Humongous Region。

分区存放:

  • 如果对象无法完全存放在一个 Region 中,则会使用多个连续的 Humongous Region。

  • 比如,32MB 的对象在默认 1MB 的 Region 大小下需要占用 32 个连续的 Humongous Region。

在老年代分配:

  • G1 会优先将 Humongous Object 分配到老年代的 Region 中,而不是年轻代。

  • 这样可以减少对年轻代垃圾回收的影响,因为年轻代频繁的 Minor GC 不适合处理大对象。


03
注意事项


内存碎片化:

  • 由于 Humongous Object 必须存放在连续的 Humongous Region 中,如果堆内存的连续空间不足,可能导致内存碎片化问题。

影响垃圾回收效率:

  • Humongous Object 一旦存放在老年代,需要触发 Full GC 才能清理这些区域,可能对系统性能造成影响。

避免频繁分配大对象:

  • 频繁创建和销毁大对象会增加垃圾回收的压力。可以通过优化代码逻辑或调整对象设计来避免这种情况。


04
调优方法


调整 Region 大小:

  • 可以通过 JVM 参数 -XX:G1HeapRegionSize 设置 Region 大小(如 1MB、2MB、4MB 等)。

  • 增大 Region 大小可以减少 Humongous Object 使用的连续 Region 数量。

避免频繁分配大对象:

  • 优化代码,减少大对象分配。例如,尽量复用大数组或缓冲区,避免频繁创建和销毁。

监控大对象分配:

  • 使用 GC 日志或工具(如 JVisualVM、JMC)监控 Humongous Object 的分配和回收情况。

启用堆碎片整理:

  • G1 GC 的标记-整理(Mark-Compact)阶段可以整理堆内存碎片,确保连续内存空间的可用性。


05
总结


当 G1 GC 遇到一个 32MB 的大对象时(其实不管是32M还是大于32M都是,不要被默认1-32M所误导),它会将该对象存储在连续的 Humongous Region 中,优先放入老年代。为了减少大对象对垃圾回收性能的影响,开发时应尽量避免频繁分配大对象,必要时可以通过调整 Region 大小来优化。


今天的内容就分享到这儿,喜欢的朋友可以关注,点赞。有什么不足的地方欢迎留言指出,您的关注是我前进的动力!


END


扫码关注

一起积累后端知识
不积跬步,无以至千里
不积小流,无以成江海

喜欢此内容的人还喜欢

谈谈id那些事(五)——美团的 Leaf 的ID生成


一个阿里二面面试官必问的问题


Lambda表达式说爱你不容易


分享面试:mysql数据库索引失效的情况


Spring-Boot中一个不起眼的好工具StopWatch