JVM日志参数十全大补丸
共 6088字,需浏览 13分钟
·
2021-09-18 07:13
作者丨安琪拉的博客
来源丨安琪拉的博客
快吃下这颗JVM十全大补丸,妈妈再也不担心JVM日志看不懂了!
本文需要一些JVM的储备知识,如果对JVM内存区域还不熟悉,可以看看基础知识部分,在JVM群里提问,评论区留言都可以,安琪拉玩家都很热心,社区很随意。
实践JVM日志
我们先打印点GC日志实践一下,再开始讲后面的理论。
首先在IDEA 中设置打印GC的参数,比如我设置的参数如下,堆、新生代老年代都设置的比较小,这样比如容易出GC日志。
-Xms56m -Xmx56m -Xmn21m -Xss512k -XX:MetaspaceSize=12m -XX:MaxMetaspaceSize=12m -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps
写一段普通的程序,for循环往Map里面塞东西,然后主动触发GC。
public class GCLogTest {
private static Map<String, String> mapContainer = new HashMap<>();
public static void main(String[] args) {
String stringDataPrefix = "key_prefix_";
for (int i = 0; i < 3000000; i++) {
String newStringData = stringDataPrefix + i;
mapContainer.put(newStringData, newStringData);
}
System.out.println("MAP size: " + mapContainer.size());
System.gc(); // 明显的GC
// 移除 2/3
for (int i = 0; i < 2000000; i++) {
String newStringData = stringDataPrefix + i;
mapContainer.remove(newStringData);
}
System.out.println("MAP size: " + mapContainer.size());
System.gc();
System.out.println("End of program!");
}
}
我们开始讲解GC日志,下面是完整的GC日志,我们分段讲解。
JVM问题场景
一般JVM平常大家不会去关注,一出问题往往还都是大问题,比如线上突然FGC徒增啦!下面讲讲常见的几种JVM问题:
年轻代:young gc时间很长,比如十几秒,甚至几十秒,这种都是很不正常,一般是swap打开了。
年轻代:young gc过于频繁,一般调大堆或者年轻代,或者把Eden区域和Survivor区域比重调一下能解决。
FullGC过于频繁一般是调大堆或者老年代能解决,当然前期是没有内存泄漏。
内存碎片过多触发cms,可以在凌晨业务低峰的时候主动触发Full GC。
程序本身代码有问题,导致内存泄露,或者gc严重,甚至oom,可以dump内存快照,自己通过MAT等工具分析,如果希望社区帮忙排查,丢到JVM群大家一起分析。
JVM参数大全
下面讲解一下常见的一些JVM 参数,吃下这颗十全大补丸。
整个堆大小 = 年轻代大小 + 年老代大小 + 持久代大小. JDK1.8以后没有持久代,而是换成了Metaspace(元数据),这块空间不属于堆。
常见的配置项先列出来:
-server : 服务器模式,JVM有客户端和服务器二种模式,最主要的差别在于:-Server模式启动时,速度较慢,但是一旦运行起来后,性能将会有很大的提升。JVM工作在Server模式下可以大大提高性能,Server模式下应用的启动速度会比client模式慢大概10%,但运行速度比Client VM要快至少有10倍。-client : 客户端模式,与上面的对应
-Xms:初始堆大小,默认大小是物理内存的1/64(<1GB),默认剩下的堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制,这个比例MinHeapFreeRatio参数可以调整。
-Xmx:最大堆大小,物理内存的1/4(<1GB),默认剩余堆内存大于70%时,JVM会缩小堆大小,直到 -Xms的最小限制这个比例可以通过MaxHeapFreeRatio参数调整。
-Xmn:年轻代大小(JDK >=1.4),Minor GC发生的地方。大小 = eden+ 2 survivor space。增大年轻代后, 将会减小年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
-XX:NewSize 也是年轻代大小 (JDK < 1.4),跟Xmn功能一样。
-XX:PermSize :持久代初始值,JDK1.8 采用Metaspace(元数据),没有这玩意了,默认值是物理内存的1/64。
-XX:MaxPermSize : 持久代最大值, 默认物理内存的1/4。
-Xss:每个线程的栈大小,都知道线程调用局部变量都在栈中,函数调用就是压栈弹栈,JDK5.0 以后每个线程堆栈大小为1M, 以前每个线程堆栈大小为256K,应用一般根据自己的特性,进行调整,比如调用层次嵌套很深,可以设置大一点。在相同物理内存下,减小这个值能生成更多的线程.但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右,一般小的应用, 如果栈不是很深, 应该是128k够用的 大的应用建议使用256k。这个选项对性能影响比较大,需要严格的测试。
-XX:NewRatio :年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代),-XX:NewRatio=4表示年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5,一般大部分时候设置了 Xms=Xmx 并且设置了Xmn的情况下,该参数不需要进行设置,这个参数不那么需要被关注。
-XX:SurvivorRatio :Eden区与Survivor区的大小比值,设置为8, 则两个Survivor区与一个Eden区的比值为2:8, 一个Survivor区占整个年轻代的1/10。
-XX:+DisableExplicitGC :禁止System.gc(),也就是你在程序中写了System.gc()不会生效。
-XX:MaxTenuringThreshold :垃圾最大年龄,
-XX:+UseBiasedLocking :可以设置是否开启锁的偏向,关于锁偏向,synchronized锁膨胀会有,可以看我之前写的 一个synchronized跟面试官扯了半个小时
-XX:PretenureSizeThreshold :对象超过多大是直接在旧生代分配
-XX:+CollectGen0First :FullGC时是否先YGC
收集器有关参数
并行收集器相关参数
-XX:+UseParallelGC :选择垃圾收集器为并行收集器,此配置仅对年轻代有效
-XX:+UseParNewGC :设置年轻代为并行收集,可与CMS收集同时使用,jdk1.8建议才用 ParNew + CMS
-XX:ParallelGCThreads : 并行收集器的线程数, 一般等于CPU核数比较合适
-XX:+UseParallelOldGC :年老代垃圾收集方式为并行收集(Parallel Compacting)
-XX:MaxGCPauseMillis :每次年轻代垃圾回收的最长时间(最大暂停时间)
-XX:GCTimeRatio :设置垃圾回收时间占程序运行时间的百分比
-XX:+ScavengeBeforeFullGC :Full GC前调用YGC
CMS相关参数
-XX:+UseConcMarkSweepGC :使用CMS内存收集,如果用CMS,一般就用xmn参数设置年轻代,不用-XX:NewRatio等。注意最新的JVM版本,当使用-XX:+UseConcMarkSweepGC时,-XX:UseParNewGC会自动开启。因此,如果年轻代的并行GC不想开启,可以通过设置-XX:-UseParNewGC来关掉。
-XX:CMSFullGCsBeforeCompaction :多少次后进行内存压缩,由于并发收集器不对内存空间进行压缩, 整理, 所以运行一段时间以后会产生"碎片",使得运行效率降低.此值设置运行多少次GC以后对内存空间进行压缩,整理。
-XX+UseCMSCompactAtFullCollection :在FULL GC的时候, 对年老代的压缩。CMS是不会移动内存的, 因此, 这个非常容易产生碎片, 导致内存不够用, 因此, 内存的压缩这个时候就会被启用。增加这个参数是个好习惯。可能会影响性能, 但是可以消除碎片。
-XX:+UseCMSInitiatingOccupancyOnly :命令JVM不基于运行时收集的数据来启动CMS垃圾收集周期,使用手动定义初始化,定义开始CMS收集,JVM通过CMSInitiatingOccupancyFraction的值进行每一次CMS收集,而不仅仅是第一次。
-XX:CMSInitiatingOccupancyFraction :默认为68,即当年老代的空间使用率达到68%时,会执行一次CMS回收。如果应用程序的内存使用率增长很快,可以根据应用特点,可以对该值进行调优,如果内存增长缓慢,则可以设置一个稍大的值,大的阈值可以有效降低CMS的触发频率,减少年老代回收的次数可以较为明显地改善应用程序性能。反之,如果应用程序内存使用率增长很快,则应该降低这个阈值,以避免频繁触发年老代串行收集器。
额外配置信息
-XX:+PrintGC 打印GC,输出形式:[GC 16384K->2544K(18944K), 0.0094143 secs] 、[Full GC 16384K->2544K(18944K), 0.0650971 secs]
-XX:+PrintGCDetails 打印详细GC,这个参数我们上面例子已经用过了。
-XX:+PrintGCTimeStamps 这个就是上面的格式打印GC的时间戳,格式参考:2021-04-01T23:35:41.454-0800
-XX:+PrintGCApplicationStoppedTime 打印垃圾回收期间程序暂停的时间
-XX:+PrintGCApplicationConcurrentTime 打印每次垃圾回收前,程序未中断的执行时间
后续
昨天JVM群里有人贴出了一些GC日志截图,大家兴致很高,就写了这篇日志查看文给大家扫清看日志的障碍。
大家感兴趣可以加我微信:guofu-angela ,JVM群学习群还有坑位。
现在微信推送机制改了,为了防止大家漏看每天的推送,建议星标一下安琪拉的博客。
-End-
最近有一些小伙伴,让我帮忙找一些 面试题 资料,于是我翻遍了收藏的 5T 资料后,汇总整理出来,可以说是程序员面试必备!所有资料都整理到网盘了,欢迎下载!
面试题
】即可获取