jvm 老年代和新生代比例多少合适_JVM 垃圾收集器细节补充

禁用 System.gc()

System.gc() 会显式直接触发 Full GC,同时对老年代和新生代进行回收。JVM 的内存回收都是自动的,一般情况下不需要我们手动触发 GC。因此如果要在程序中禁用,可以通过-XX:+DisableExplicitGC禁用。当程序中使用了System.gc(),就相当于调用了一个空函数。

对象何时进入老年代

一般情况下,新创建的对象会出现在新生代的 Eden区。对于存活时间长的对象,进入老年代的情况有以下2种:

  • 普通对象晋升老年代

JVM 中提供了 -XX:MaxTenuringThreshold=15 这个参数来指定,普通对象晋升老年代经历的GC的最大次数。这个参数值默认是15,当然对象往往不到15次GC就已经进入了老年代。

晋升中还有一个比较重要的参数,-XX:TargetSurvivorRatio=50。它用来指定suvivor区的使用率达到50%时(默认值),触发晋升老年代。

  • 大对象直接进入老年代

通常来说,我们对于Java项目的堆分配,老年代会占到一大半的容量。所以当新生代(Eden/Survivor)容量不足时,新创建的大对象会直接进入老年代。

我们可以通过 -XX:PretenureSizeThreshold (单位字节)来指定直接晋升老年代的对象大小。但是在测试时往往会出现以下情况,对象达到设置大小并未进入老年代。这是因为JVM在使用内存空间时,会优先使用一块TLAB的区域。

TLAB(Thread Local Allocation Buffer)是线程本地分配缓存。它占用了 Eden区的空间,JVM 会为每一个Java线程分配一块 TLAB空间。启用参数是:-XX:+UseTLAB (JVM默认开启)。

对象分配简要流程

我们所熟知的是对象是在对上分配的,但是对象的分配大致会经历以下几个流程。首先会尝试在栈上分配,栈上分配的对象会随着方法块的执行结束,而自动被回收。如果失败了,则会尝试TLAB分配。如果再失败了,则会检查是否满足直接进入老年代的条件,满足则在老年代分配。如果不满足,则在Eden区分配。简要流程如下所示:

29b85298ddfcc375013953108c3624c8.png

对象分配简要流程

finalize() 对 GC 的影响

finalize() 方法类似于C++中的析构函数,它在对象即将被GC回收器回收的时候执行1次。但是尽量不要使用finalize()对资源进行释放,尽量不要重写该方法,原因如下:

  • finalize() 可能会造成对象复活
  • 执行时间是没有保障的,它完全由 GC线程决定。极端情况下,如果不发生GC,finalize() 将不会执行
  • 如写的不好,则有可能严重影响 GC 性能

finalize() 是由 FinalizerThread 线程处理的。每个即将被回收的并且包含有finalize()方法的对象,都会被在正式回收前加入 FinalizerThread 的执行队列(为 ReferenceQueue 引用队列)。

FinalizerThread 的工作过程和FinalizerThread执行队列关系如下所示:

156d576c86b2899a3933e3f334e055cc.png

FinalizerThread 的工作过程

​​​​​​​常用 GC 参数整理

串行收集器相关

  • -XX:+UseSerialGC:在新生代和老年代使用串行收集器。
  • -XX:SurvivorRatio:设置Eden区和Survivor区的比例。设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10。
  • -XX:PretenureSizeThreshold:设置大对象进入老年代的阀值(单位字节)。
  • -XX:MaxTenuringThreshold:设置进入老年代年龄的最大值,每一次新生代GC都会加1(默认15)。

并行 GC 相关

  • -XX:+UseParNewGC:新生代使用并行收集器。
  • -XX:+UseParallelOldGC:老年代使用并行回收。
  • -XX:ParallelGCThreads:设置用户GC的线程数。通常情况下可以和CPU个数相同,但CPU较多的情况下,可以相对设置小一些。
  • -XX:MaxGCPauseMillis:设置GC最大停顿时间。
  • -XX:GCTimeRatio:设置吞吐量大小。取值0-100之间的整数。如设置为n,则系统花费不超过1/(n+1)的时间用于GC。
  • -XX:+UseAdaptiveSizePolicy:打开自适应GC策略。这种模式下,JVM的各个参数都将会被动态调整,以达到堆大小、吞吐量和停顿时间的平衡。

CMS 相关

  • -XX:+UseConcMarkSweepGC:新生代使用并行回收器,老年代使用CMS+串行回收。
  • -XX:ParallelCMSThreads:设定CMS的线程数量。
  • -XX:CMSInitiatingOccupancyFraction:设置CMS收集器在老年代使用多少后触发GC,默认68%。
  • -XX:+UseCMSCompactAtFullCollection:设置CMS收集器在完成垃圾收集后,是否要进行一次碎片整理。
  • -XX:CMSFullGCsBeforeCompaction:设定进行多少次CMS回收后,进行一次内存压缩。
  • -XX:+CMSClassUnloadingEnabled:允许对元数据区进行回收。
  • -XX:CMSInitiatingPermOccupancyFraction:当永久区使用率达到这一百分比时,启动CMS回收。(前提是CMSClassUnloadingEnabled开启)
  • -XX:UseCMSInitiatingOccupancyOnly:表示只在达到阀值的时候才进行CMS回收。
  • -XX:+CMSIncrementalMode:使用增量模式,比较适合单CPU。JDK8中废弃,JDK9中已移除。

G1 相关

  • -XX:+UseG1GC:使用G1收集器。
  • -XX:MaxGCPauseMillis:设置最大停顿时间。
  • -XX:GCPauseIntervalMillis:设置停顿间隔时间。

TLAB 相关

  • -XX:+UseTLAB:开启TLAB分配。
  • -XX:+PrintTLAB:打印TLAB相关分配信息。
  • -XX:TLABSize:设置TLAB大小。
  • -XX:+ResizeTLAB:自动调整TLAB大小。

其他

  • -XX:+DisableExplicitGC:禁用显示GC。
  • -XX:+ExplicitGCInvokesConcurrent:使用并发的方式处理显示GC。

参考:《实战Java虚拟机》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值