GC调优记录


前言

工作当中,非功能测试时,我们经常会遇到FullGC频繁的问题(通常在4C的服务器上FullGC 15分钟内触发一次视作频繁)。所以需要对JVM进行调优,这里记录一下使用的命令和工具,以及场景。

一、常用的命令

查看进程,获取进程号

ps -ef 

查看java应用信息

jinfo -flags <PID>

调用jinfo命令设置VM参数

jinfo -flag <JVM Params> <PID>

监控Java应用程序的统计信息,包括内存使用情况

jstat -gc <PID> <刷新时间(毫秒)>

生成Java堆内存的转储文件

jmap -dump:format=b,file=<输出文件名> <PID>

打开visualVM

jvisualvm

打开jconsole

jconsole

二、visualVM以及jconsole远程连接

1.修改JMX远程连接的配置

-Djava.rmi.server.hostname=10.223.51.30 
-Dcom.sun.management.jmxremote.port=1232 
-Dcom.sun.management.jmxremote.rmi.port=1240  
-Dcom.sun.management.jmxremote.ssl=false 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.local.only=false

如果有权限验证-Dcom.sun.management.jmxremote.authenticate=true,需要添加用户名和密码:

-Dcom.sun.management.jmxremote.access.file = "权限文件地址"
-Dcom.sun.management.jmxremote.password.file = "用户名密码文件地址"

2.打开监控工具

VisualVM配置远程连接连接,jconsole和VisualVM类似配置即可。
在这里插入图片描述
-Djava.rmi.server.hostname=10.223.51.30 主机名
-Dcom.sun.management.jmxremote.port=1232 端口

三、具体场景

问题一:堆内存比较大应该使用什么垃圾收集器?

答:G1非常适合超大内存的机器。因为内存太大,不用G1会导致新生代每次GC回收垃圾太多,停顿太长。使用G1则可以指定每次GC停顿时间,每次回收一部分Region。

问题二:

从GC效果上看,G1最明显的特点就是可以预测STW的时间。G1为了达到这个效果,抛弃传统分代内存,分成各个小内存块Region。针对这些Region计算垃圾回收价值,然后选某些性价比高的进行GC,以便在预先设定的GC时间内完成GC。所以是不是G1可以用在对STW特别敏感的业务上?比如实时通信等追求低延迟响应的业务。

答:是的。还有就是那种大内存机器,比如16G,32G的机器部署的系统。大内存机器如果不用G1,那么新生代满时对象太多,一次GC时间太长。而用了G1则可以控制停顿时间,每次只回收部分Region即可。

问题三:

G1按Region回收会不会形成新的内存碎片?

答:不会。Region回收时使用的是复制算法,会将存活对象拷贝到其他Region。然后再对原来的Region直接回收掉全部垃圾。

问题四:

G1分那么多Region,有点像HDFS里的小文件,小文件太多会影响性能。但是为什么G1的性能会比之前那些更好?

答:划分为很多的Region,回收时按照设定只能停顿系统20ms。所以就会挑选少量Region来回收,这样可以控制垃圾回收的停顿时间。如果按照ParNew + CMS组合简单分代划分,必须回收整个新生代。这时每次GC回收的内存区域大了,必然要停顿更久时间。

问题五:

一个Spring Boot应用在8G内存开发机上跑,启动需要加载的类特别多。每次JVM一启动,新生代就以每秒10M的速度增长,光启动就要十分钟。因为发现启动期间就进行了两次Full GC,半小时执行了十几次YGC。于是就调整了新老比例为2比1,共分配4G。之后FGC一直为0, YGC半小时只有两次,启动时间也降为1分钟以内。

答:是的,这就是典型的新生代内存不足导致的。系统启动时要创建一堆对象,发现新生代不够。于是频繁YGC,很多对象进入到老年代。然后老年代又不足,又要对老年代Full GC。最后就出现十多次YGC + 几次Full GC。

由于GC太多会导致系统启动速度很慢。优化比例后,新生代内存充足,很多对象直接进入新生代不用进老年代。于是最多就是少数YGC回收一部分对象,也不会有FGC。GC次数减少了,那系统启动速度也就快了。

问题六:

G1垃圾回收器也应该合理分配新生代的占比,保证S区足够大。不让存活对象很快进入老年代,不让老年代很快占到45%。如果老年代不那么快占到45%,自然就可以减少混合回收。

问题七:

一.G1混合回收在第四个阶段会进行多次混合回收,这个多次混合回收的间隔是由G1自己控制的。

二.空闲的Region数量达到堆内存5%就会停止回收,即默认最多进行8次混合回收。但可能到了4次,发现空闲Region达到5%就不进行混合回收了。

三.Mixed GC回收失败时Full GC,应该是采用Serial Old回收器。

二、G1参数设置

-XX:+UseG1GC:使用G1收集器

-XX:ParallelGCThreads:指定GC工作的线程数量

-XX:G1HeapRegionSize:指定分区大小(1MB~32MB,且必须是2的N次幂),默认将整堆划分为2048个分区

-XX:MaxGCPauseMillis:目标暂停时间(默认200ms)

-XX:G1NewSizePercent:新生代内存初始空间(默认整堆5%,值配置整数,默认就是百分比)

-XX:G1MaxNewSizePercent:新生代内存最大空间

-XX:TargetSurvivorRatio:Survivor区的填充容量(默认50%),Survivor区域里的一批对象(年龄1+年龄2+年龄n的多个年龄对象)总和超过了Survivor区域的50%,此时就会把年龄n(含)以上的对象都放入老年代

-XX:MaxTenuringThreshold:最大年龄阈值(默认15)

-XX:InitiatingHeapOccupancyPercent:老年代占用空间达到整堆内存阈值(默认45%),则执行新生代和老年代的混合收集(MixedGC),比如我们之前说的堆默认有2048个region,如果有接近1000个region都是老年代的region,则可能就要触发MixedGC了

-XX:G1MixedGCLiveThresholdPercent(默认85%) region中的存活对象低于这个值时才会回收该region,如果超过这个值,存活对象过多,回收的的意义不大。

-XX:G1MixedGCCountTarget:在一次回收过程中指定做几次筛选回收(默认8次,每次都STW,垃圾回收和应用线程来回执行),在最后一个筛选回收阶段可以回收一会,然后暂停回收,恢复系统运行,一会再开始回收,这样可以让系统不至于单次停顿时间过长。

-XX:G1HeapWastePercent(默认5%): gc过程中空出来的region是否充足阈值,在混合回收的时候,对Region回收都是基于复制算法进行的,都是把要回收的Region里的存活对象放入其他Region,然后这个Region中的垃圾对象全部清理掉,这样的话在回收过程就会不断空出来新的Region,一旦空闲出来的Region数量达到了堆内存的5%,此时就会立即停止混合回收,意味着本次混合回收就结束了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值