Jvm 内存分配和回收策略

121 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第 15 天,点击查看活动详情

1 前言

在前文中我们已经讲述了三款垃圾回收器的内容,在本文中将继续分享有关 jvm 内容,jvm 的内存分配和回收策略。jvm 的自动内存管理,主要解决的问题有两个:给对象分配内存以及自动回收分配给对象的内存。

2 对象优先在 Eden 分配

大多数情况下,对象都是在堆上进行分配,而且在 Eden 去进行分配,当 Eden 去没有足够的空间分配时,虚拟机将会触发 Minor GC 。

# 打开收集器日志的参数
-XX:+PrintGCDetails
# 新生代中Eden区与Survivor区的空间比例是8∶1
-XX:Survivor-Ratio=8

一般情况下,对象都是在堆上进行分配,但是如果开启了逃逸分析,则对象可能直接进行栈上分配,这样就可以省去垃圾回收的过程。

3 大对象直接进入老年代

一般情况下,大对象进入老年代超过一定的数值后,就会直接进入老年代中,避免 Eden 区和 Survivor 区之间进行来回复制,以节省操作。大对象进入老年代的参数设置只对 Serial 和 ParNew 两款新生代收集器有效, Parallel Scavenge 对这个参数并不支持。

# 大对象进入老年代的条件,默认值为 3MB。
-XX:PretenureSizeThreshold

4 长期存活的对象进入老年代

通常情况下,对象在 Eden 区诞生,经历过一次 Minor GC 后仍然存活,并且能够在 Survivor 中存活,则对象的 GC 年龄+1 , 同样的对象如果在 Survivor 进行一次 GC 操作,GC 年龄同样会增加 1。当对象的 GC 年龄达到 15 时,则自动晋升到老年代中。

# 大对象晋升到老年代的阈值
-XX:MaxTenuringThreshold=15

5 动态对象年龄判定

在 HotSpot 虚拟机中并不是永远要求对象达到晋升年龄才能到老年代,如果在 Survivor 空间中相同年龄所有对象的大小综合大于 Survivor 空间的一半,则年龄大于或者等于该年龄的对象就可以直接晋升到老年代,而不需要等到晋升年龄。

6 空间分配担保

jvm 在发生 Minor GC 之前,虚拟机必须先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果这个条件成立,那么这一次 Minor GC 可以执行,如果不成立,那么虚拟机会检查是否检查允许分配担保失败,如果允许则会检查老年代的最大可用连续空间是否大于历次晋升到老年代对象的平均大小,如果大于则可以尝试进行一次 Minor GC,否则就不允许担保失败,因此就需要进行一次 Full GC。

# 是否开启允许担保失败
-XX:HandlePromotionFailure

7 总结

在本文中,讲述了对象的分配规则,以及大对象内存管理的内容,最后分享了空间分配担保机制,在后续的文章中,将会继续分享 jvm 相关的内容。