后端调优基础——GC调优

本文详细介绍了Java后端的GC调优,包括GC类型、触发条件、GC日志解析、各种GC收集器的工作原理及参数设置,强调了减少Full GC的重要性,并提供了CMS和G1收集器的优化策略,旨在提升系统性能和稳定性。
摘要由CSDN通过智能技术生成

GC类型

  • Minor GC :清理新生代,Minor GC是最频繁触发的GC,速度也最快的,主要工作原理是:
    对象在young区的eden创建,当eden空间满后触发Minor GC,将还存活的对象复制到一个survivor0中,另一个survivor1也会将对象复制过去,然后对eden和survivor1进行全部清理,survivor0和survivor1就这样不断交替,总有一个是空着的,当对象放不下或者是对象年龄足够老(默认15)会将其放入Old区,由此可见Minor GC时不但会清理对象,还会将对象放入Old区。

可以通过设置-XX:MaxTenuringThreshold=n来指定对象经过多少次Minor GC后就进入Old 区,默认15
可以通过设置-XX:SurvivorRatio=n设置Survivor区和eden区的比例,如-XX:SurvivorRatio=8 那么比例就是8:1:1 ,没有设置的话就以-XX:InitialSurvivorRatio=n为默认设置,这个值默认是8

  • Major GC :清理老年代,Major GC比Minor GC慢十倍以上,单独触发Major GC只有CMS和G1有这个能力,因为cms和G1处理老年代不需要触发full gc,其他的老年代回收器回收老年代需要触发full gc。
  • Full GC: 清理整个堆空间,包括新生代、永久代和老年代,它会启动老年代收集器和新生代收集器一起工作,全程Stop The World,尽量避免Full GC

Full gc:

full gc是对新生代,老年代、永久久代的统一回收,由于是对整个空间的回收,并且会触发系统的停顿(stop-the-world),因此应当尽量的减少系统full gc的次数。

触发的full gc的几个条件

  • 老年代空间不足:新生代如果容量不足会将对象放到老年代,老年代空间不足是会触发full gc,通过-Xmn设置新生代大小,也可以通过-XX:NewRatio=n设置比例,默认值是2,老年代:新生代=》2:1
  • 永久代空间不足:永久代在jdk7是存放在堆中的,可以通过-XX:PermSize=n-XX:MaxPermSize=n设置大。
    在jdk8中叫做元空间,使用的是计算机的本地内存通过-XX:MaxMetaspaceSize=n设置大小,如果不设置,默认最大内存大小是计算机的本地内存,由于运行时常量池在方法区中,而永久代又是方法区的实现,所以运行时常量池随着jdk8也移动到了本地内存,但是无论是jdk7还是jdk8,字符串常量池还是在堆中,字符串常量的创建是需要消耗堆内存的
  • CMS 产生碎片过多已经扛不住压力了就会调用full gc进行整合:可以通过-XX:CMSFullGCsBeforeCompaction=n设置要执行多少次full GC才会做压缩。默认是0,也就是每次full gc时就会对空间碎片进行整理,在默认配置下如果碎片过多CMS GC顶不住了,就要转入full GC的时候都会做压缩。(如果Full GC比较频繁,那么就不能每次都整理内存空间,不然积少成多,停顿的时间也是很可观的,此时就要调大该参数,让CMS在经过多次Full GC后再对内存空间进行压缩整理,而如果Full GC发生的不频繁,间隔时间较长,就可以设置成每次Full GC后都会对内存空间进行压缩整理,影响也不大。)
  • CMS GC时出现了promotion failed和concurrent mode failure:
    1、promotion failed意思是晋升失败是由于新生代把一些对象往老年代扔,然后老年代空间不足则抛出“promotion failed”,触发full gc,可能的原因是:Survivor空间过小或者老年代空间小或者碎片多,或者两者同时发生2、concurrent mode failure是CMS设置启动的老年代内存占比阈值过高,所以导致系统无法预留足够的空间满足程序需求,就会出现concurrent mode failure,启动担保机制,老年代增长过快触发full gc进行清理,解决方法是降低触发CMS的阀值,使用-XX:CMSInitiatingOccupancyFraction调低阈值,默认值是68,可以调到50
  • 统计得到新生代minor gc时晋升到老年代的平均大小大于老生代剩余空间
    原因有几个:1、代码问题大量大对象直接进入老年代 2、老年代空间不足,通过-XX:NewRatio=n可以调整老年代和年轻的堆比例
  • 代码直接调用System.gc()会建议系统调用full gc:在GC日志中会显示为[Full GC(System),可以开启-XX:-DisableExplicitGC禁止此类full gc

GC日志

通过设置系统参数:-XX:+PrintGCDetails可以GC日志打印到控制台,以下几个命令可以设置GC日志

    -XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)
    -XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2020-10-23T21:53:59.234+0800)
    -XX:+PrintGCDetails   打印出GC的详细信息
    -verbose:gc  开启gc日志   开启这个按钮后就算是使用了+PrintGCDetails也无法在控制台看到,因为打印的内容会到日志文件中
    -Xloggc:d:/gc.log   gc日志的存放位置

实战:

image.png

运行这段代码,由于堆内存被这些常量占满,马上就会触发gc了

public class Tzb {
    public static void main(String[] args) {
        while (true){
            String str=System.currentTimeMillis()+ UUID.randomUUID().toString();
            str.intern();
        }
    }
}

打印了下列的内容,我把它们一部分复制出来

image.png

-XX:InitialHeapSize=1048576 -XX:MaxHeapSize=1048576 -X
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值