Java JVM 1: 常用GC与参数

如今JVM的GC越来越优秀,回收效率越来越高,但即使再牛的GC目前也无法做到完全不需要“stop-the-world”,G1也是,可能这就是C++这类语言可以手动管理内存的优势了。

垃圾收集器

串行(Serial)回收器

新生代串行回收器:复制算法
老年代串行回收器:标记整理算法
特点:单线程,”Stop-The-World”,用户体验差但是技术成熟,适合单CPU等硬件性能较差的场合。所以说具体选择什么样的GC还是依据实际场景而定,不可脱离实际泛泛而谈。
参数

  • -XX:+UseSerialGC
    指定使用新生代串行回收器和老年代串行回收器。
并行(Parallel)回收器

新生代ParNew回收器:只是将串行回收器多线程化,回收策略和算法等方面类似串行回收器。

下面两种ParallellGC是java9以前JVM 的缺省收集器,通过GC日志也能看出。
新生代ParalellGC回收器:关注吞吐量(throoughput),还可以开启参数-XX:+UseAdaptiveSizePolicy使得GC自适应调节堆大小、吞吐量和停顿时间之间的平衡。
老年代ParalellOldGC回收器:关注吞吐量,标记整理算法,和新生代ParalellGC配合使用。
参数

  • -XX:+GCTimeRatio
    设置吞吐量大小(jvm用于内存回收的时间的比例),0到100的整数。若为n,则花费不超过1/(n+1)的时间用于垃圾收集。
  • -XX:+MaxGCPauseMillis
    设置最大垃圾收集停顿时间,GC会调整java堆大小或者其他参数尽可能将停顿时间控制在MaxGCPauseMillis内。若设置很小的值,虚拟机为达到预期停顿时间,虚拟机可能会分配一个较小 的堆以加快回收,但这会导致回收变得频繁从而降低吞吐量。

这两个参数在某种程度上是矛盾的,通常减少一次收集的最大停顿时间就会降低吞吐量,而增加吞吐量则可能会增加一次垃圾回收的最大停顿时间。这很好理解,比如我们调小MaxGCPauseMillis,单次停顿时间降低了,内存空间会调小,继而更容易被耗尽,那么GC的执行频率就上升了,总的GC时间还是会上升,也就是吞吐量下降了。

CMS(Concurrent Mark Sweep)回收器

关注系统停顿时间

cms流程

需要注意的是,CMS收集器无法处理“浮动垃圾”(Floating Garbage),可能出现“Concurrent Mode Failure”失败而导致另一次Full GC的产生。由于CMS并发清理阶段用户线程还在运行着,伴随程序的运行自然还会有新的垃圾不断产生,这一部分垃圾出现在标记过程之后,CMS无法在本次收集中处理掉它们,只好留待下一次GC时再将其清理掉。这一部分垃圾就称为“浮动垃圾”。因此CMS收集器不能像其他收集器那样等到老年代几乎完全被填满了再进行收集,需要预留一部分空间提供并发收集时的程序运作使用。在默认设置下,CMS收集器在老年代使用了68%的空间后就会被激活。可设置-XX:CMSInitiatingOccupancyFraction参数调整。
还有一个缺点,CMS是一款基于“标记-清除”算法实现的收集器,这意味着收集结束时会产生大量空间碎片。空间碎片过多时,将会给大对象分配带来很大的麻烦,往往会出现老年代还有很大的空间剩余,但是无法找到足够大的连续空间来分配当前对象,不得不提前触发一次Full GC。

参数

  • -XX:CMSInitiatingOccupancyFraction
    提高触发百分比,以便降低内存回收次数以获取更好的性能。设置得太高将会很容易导致大量“Concurrent Mode Failure”失败,性能反而降低,实际应用中注意权衡。
  • -XX:+UseCMSCompactAtFullCollection
    Full GC服务之后额外附加一个碎片整理过程,内存整理的过程是无法并发的。可以解决空间碎片问题,但停顿时间变长了。
  • -XX: CMSFullGCsBeforeCompaction
    设置在执行多少次不压缩的Full GC后,跟着来一次带压缩的。
G1回收器

目前java9中G1已经被设置为默认回收器。
G1垃圾收集器在JDK7 update 4之后对大于4G的堆有了更好的支持,G1是一个针对多处理器大容量内存的服务器端的垃圾收集器,其目标是在实现高吞吐量的同时,尽可能的满足垃圾收集暂停时间的要求。G1在执行一些Java堆空间中的全区域操作(如:全局标记)时是和应用程序线程并发进行的,因此减少了Java堆空间的中断比例。(译者注:可简单理解为减少了Stop-the-World的时间比例)。
它与前面的CMS收集器相比有两个显著的改进:一是G1收集器是基于“标记-整理”算法实现的收集器,也就是说它不会产生空间碎片,这对于长时间运行的应用系统来说非常重要;二是它可以非常精确地控制停顿,既能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒,具备了一些实时Java(RTSJ)的垃圾收集器的特征。
首先将Java堆空间划分为一些大小相等的区域(region),每个区域都是虚拟机中的一段连续内存空间。G1通过执行并发的全局标记来确定整个Java堆空间中存活的对象。标记阶段完成后,G1就知道哪些区域基本上是空闲的。在回收内存时优先回收这些区域,这样通常都会回收相当数量的内存。这就是为什么它叫做Garbage-First的原因。顾名思义G1关注某些区域的回收和整理,这些区域中的对象很有可能被完全回收。而且G1使用了一个暂停时间预测模型使得暂停时间控制在用户指定的暂停时间内,并根据用户指定的暂停时间来选择合适的区域回收内存。
G1确定了可回收的区域后就是筛选回收(evacuation)阶段了。在此阶段将对象从一个或多个区域复制到单一区域,同时整理和释放内存。该阶段是在多个处理器上多个线程并行进行的,因此减少了暂停时间并提高了吞吐量。G1在每一次的垃圾收集过程中都不断地减少碎片,并能够将暂停时间控制在一定范围内。这些已经是以前的垃圾收集器无法完成的了。比如:CMS收集器并不做内存整理。ParallelOld收集器只是对整个Java堆空间做整理,这样导致相当长的暂停时间。

常用JVM参数

堆内存参数配置
  • -Xms 初始堆的大小
  • -Xmx 最大堆大小,一般与初始堆大小设为一样
  • -Xmn 新生代的大小
  • -XX:NewRatio 老年代/新生代
  • -XX:SurvivorRatio 新生代中eden区/from(to)区

    这里写图片描述
非堆内存参数配置
  • -Xss 线程栈
  • -XX:PermSize 初始永久区
  • -XX:MaxPermSize 最大永久区
    1.8中不再有永久区,而是用元数据区存放类的元数据,默认情况下,元数据区大小只受系统可用内存限制,但是可以使用参数-XX:MaxMetaspaceSize指定大小

参考
《实战Java虚拟机》
https://tech.meituan.com/g1.html
https://yq.aliyun.com/articles/49058
并发编程网JVM实用参数系列

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值