JVM高频参数
- 一、常用参数配置
- 1. 堆内存设置
- 方式1(Java8及之前)
- 方式2(Java9及之后)
- 2. 新生代和老年代设置
- 3. 垃圾收集器选择
- 4. 调试和日志
- 5. Metaspace设置
- 6. 其他重要参数
- 二、参数设置最佳实践
- 三、GC日志
- 参数设置
- 日志解析
- MinorGC
- FullGC
- 日志分析工具
一、常用参数配置
1. 堆内存设置
方式1(Java8及之前)
- -Xms:设置初始堆大小。
- -Xmx:设置最大堆大小。
为什么会存在两个堆大小的参数呢?
这里涉及到一个资源利用的问题。一般而言服务的访问量都是存在起伏的,为了最大化利用系统资源,加入初始大小设置(初始堆大小小于最大堆大小),在低谷期分配一个较小的堆空间的话不会浪费系统内存资源,而在之后访问量上升的时候,JVM再动态扩容,直到扩至最大堆限制;
Xms和Xmx设置不同有好处也有坏处:
- 好处是设计初衷,合理利用系统资源
- 坏处是服务启动初期可能会由于堆内存不够用而频繁GC、影响性能
一般情况下建议两个设置相同即可
方式2(Java9及之后)
直接用Xms和Xmx的方式设置堆大小的方式是有缺陷的,比如云端集群化的服务,动态调整服务资源的时候,需要同时手动调整两个参数,Java9引入了新的参数,堆大小不必明确设定一个值,设定为一个系统内存的比例即可,这样机器或者容器内存调整的时候堆内存大小也会跟随动态调整;
- -XX:+UseContainerSupport:设置JVM检测所处容器(而不是整个操作系统)的内存大小和处理器数量
- -XX:InitialRAMPercentage=70.0:设置初始堆大小占容器内存比例。
- -XX:MaxRAMPercentage=70.0:设置最大堆大小占容器内存比例。
2. 新生代和老年代设置
- -XX:NewRatio=:设置新生代与老年代的比例。
- 默认值为2,也就是说新生代和老年代默认比例是1:2,但是根据实际服务的情况可以调整为1;
- -XX:SurvivorRatio=:设置Eden区和Survivor区的比例。
- 默认值为8,也就是Eden和s1、s2默认比例是8:1:1,这里也可以根据实际情况多分配一些给s区;
- -XX:MaxTenuringThreshold=:设置对象在新生代的最大存活年龄。
- 默认15,即经过了15轮minorGC之后就晋升到老年代;
- -XX:PretenureSizeThreshold:设置直接晋升老年代的对象大小。
- 默认为0,即默认都走晋升机制
3. 垃圾收集器选择
- -XX:+UseSerialGC:使用串行垃圾收集器。
- -XX:+UseParallelGC:使用并行垃圾收集器。
- -XX:+UseG1GC:使用G1垃圾收集器。
- -XX:+UseConcMarkSweepGC:使用CMS垃圾收集器。
4. 调试和日志
- -XX:+PrintGCDetails:打印垃圾回收详细信息。
- -XX:+PrintGCDateStamps:在GC日志中添加时间戳。
- -Xloggc::将GC日志输出到指定文件。
5. Metaspace设置
- -XX:MetaspaceSize=:设置Metaspace的初始大小。
- -XX:MaxMetaspaceSize=:设置Metaspace的最大大小。
6. 其他重要参数
- -XX:PretenureSizeThreshold=:设置大对象直接分配到老年代的阈值。
- -XX:+UseCompressedOops:启用压缩指针以节省内存(适用于64位JVM)。
PretenureSizeThreshold默认是0,也就是JVM默认不会直接晋升对象,而是要走默认晋升机制(15次MinorGC),实际中可以结合自己的服务特殊情况手动设置这个参数调优
二、参数设置最佳实践
JVM的堆(Heap)占用内存过大会引发如下问题:
- 如果JVM直接运行在Linux系统,可能会导致Java进程被Linux系统的OOM Killer所终止(Kill);
- 如果JVM运行在Docker容器环境,可能会表现为频繁异常重启。
以下是一套推荐的JVM配置最佳实践:
- 堆内存的指定建议用比例而不是具体值,这个一般设定为系统资源的 70%;
- GC日志建议带时间戳打印、OOM日志应该dump到文件(毕竟线上环境应该不循序随便上机jstat、jmap)
三、GC日志
参数设置
开启日志打印:-XX:+PrintGC
打印详情:-XX:+PrintGCDetails
收集到指定文件:-Xloggc:filename
开启效果:
[GC (Allocation Failure) [PSYoungGen: 65536K->10730K(76288K)] 65536K->48130K(251392K), 0.0192302 secs] [Times: user=0.19 sys=0.00, real=0.02 secs]
[GC (Allocation Failure) [PSYoungGen: 76266K->10744K(141824K)] 113666K->96048K(316928K), 0.0315212 secs] [Times: user=0.22 sys=0.00, real=0.03 secs]
[GC (Allocation Failure) [PSYoungGen: 141816K->10744K(141824K)] 227120K->203431K(335872K), 0.0629411 secs] [Times: user=0.63 sys=0.09, real=0.06 secs]
[Full GC (Ergonomics) [PSYoungGen: 10744K->0K(141824K)] [ParOldGen: 192687K->186800K(419328K)] 203431K->186800K(561152K), [Metaspace: 3310K->3310K(1056768K)], 1.1488717 secs] [Times: user=7.97 sys=0.03, real=1.15 secs]
[GC (Allocation Failure) [PSYoungGen: 131072K->10752K(196096K)] 317872K->315546K(615424K), 0.0746573 secs] [Times: user=0.66 sys=0.08, real=0.07 secs]
[Full GC (Ergonomics) [PSYoungGen: 10752K->0K(196096K)] [ParOldGen: 304794K->279194K(649216K)] 315546K->279194K(845312K), [Metaspace: 3310K->3310K(1056768K)], 1.3879980 secs] [Times: user=10.31 sys=0.00, real=1.39 secs]
[GC (Allocation Failure) [PSYoungGen: 185344K->10752K(257024K)] 464538K->464974K(906240K), 0.1053396 secs] [Times: user=0.73 sys=0.03, real=0.11 secs]
[Full GC (Ergonomics) [PSYoungGen: 10752K->0K(257024K)] [ParOldGen: 454222K->410310K(956416K)] 464974K->410310K(1213440K), [Metaspace: 3310K->3310K(1056768K)], 2.2701650 secs] [Times: user=18.20 sys=0.03, real=2.27 secs]
[GC (Allocation Failure) [PSYoungGen: 173532K->158944K(441344K)] 583843K->569262K(1397760K), 0.4728423 secs] [Times: user=3.28 sys=0.03, real=0.47 secs]
[GC (Allocation Failure) [PSYoungGen: 392416K->220661K(454144K)] 802734K->793900K(1410560K), 0.1925215 secs] [Times: user=1.63 sys=0.11, real=0.19 secs]
[Full GC (Ergonomics) [PSYoungGen: 454133K->39886K(454144K)] [ParOldGen: 755767K->956022K(1720320K)] 1209901K->995909K(2174464K), [Metaspace: 6166K->6166K(1056768K)], 5.1099882 secs] [Times: user=43.84 sys=0.11, real=5.11 secs]
[GC (Allocation Failure) [PSYoungGen: 273358K->265280K(647680K)] 1229381K->1221310K(2368000K), 0.8109806 secs] [Times: user=6.86 sys=0.08, real=0.81 secs]
[GC (Allocation Failure) [PSYoungGen: 572480K->366592K(673792K)] 1802303K->1794199K(2394112K), 1.2465647 secs] [Times: user=10.16 sys=0.14, real=1.25 secs]
[GC (Allocation Failure) [PSYoungGen: 673792K->462848K(860672K)] 2101399K->2094679K(2580992K), 1.5548847 secs] [Times: user=12.59 sys=0.22, real=1.55 secs]
[Full GC (Ergonomics) [PSYoungGen: 462848K->189566K(860672K)] [ParOldGen: 1631831K->1720296K(2746880K)] 2094679K->1909863K(3607552K), [Metaspace: 8764K->8764K(1056768K)], 11.6830036 secs] [Times: user=97.47 sys=0.01, real=11.68 secs]
Heap
PSYoungGen total 926720K, used 226946K [0x000000076b300000, 0x00000007c0000000, 0x00000007c0000000)
eden space 463872K, 48% used [0x000000076b300000,0x00000007790a0998,0x0000000787800000)
from space 462848K, 0% used [0x00000007a3c00000,0x00000007a3c00000,0x00000007c0000000)
to space 462848K, 0% used [0x0000000787800000,0x0000000787800000,0x00000007a3c00000)
ParOldGen total 2780160K, used 2541791K [0x00000006c1800000, 0x000000076b300000, 0x000000076b300000)
object space 2780160K, 91% used [0x00000006c1800000,0x000000075ca37cc8,0x000000076b300000)
Metaspace used 9298K, capacity 9666K, committed 9984K, reserved 1058816K
class space used 1074K, capacity 1162K, committed 1280K, reserved 1048576K
日志解析
这里调出两条来看看具体含义
MinorGC
[GC (Allocation Failure) [PSYoungGen: 65536K->10730K(76288K)] 65536K->48130K(251392K), 0.0192302 secs] [Times: user=0.19 sys=0.00, real=0.02 secs]
- GC 类型:[GC (Allocation Failure)]
- 表示这是一次垃圾回收(GC),因为分配失败(即无法为新的对象分配内存)。
- 年轻代信息:[PSYoungGen: 65536K->10730K(76288K)]
- 65536K:年轻代回收前的大小。
- 10730K:年轻代回收后的大小。
- (76288K):年轻代的总大小(最大可用内存)。
- 总堆信息:65536K->48130K(251392K)
- 65536K:总堆在 GC 前的大小。
- 48130K:总堆在 GC 后的大小。
- (251392K):总堆的最大可用内存。
- GC 耗时:0.0192302 secs
- 表示这次 GC 操作的持续时间为 0.0192302 秒。
- 其他信息:[Times: user=0.19 sys=0.00, real=0.02 secs]
- user=0.19:用户 CPU 时间,表示 GC 操作中消耗的用户态 CPU 时间。
- sys=0.00:系统 CPU 时间,表示 GC 操作中消耗的内核态 CPU 时间。
- real=0.02 secs:表示实际的墙钟时间,即从开始到结束的总时间。
- 总结
- 这条日志表明,在进行垃圾回收时,由于内存分配失败,年轻代的内存被回收,释放了约 54806K 的空间,GC 的处理过程花费了约 19 毫秒。此时,堆的总内存从 65536K 降低到 48130K。
FullGC
[Full GC (Ergonomics) [PSYoungGen: 454133K->39886K(454144K)] [ParOldGen: 755767K->956022K(1720320K)] 1209901K->995909K(2174464K), [Metaspace: 6166K->6166K(1056768K)], 5.1099882 secs] [Times: user=43.84 sys=0.11, real=5.11 secs]
- GC 类型:[Full GC (Ergonomics)]
- 表示这是一次完整的垃圾回收,原因是根据 JVM 的自动调节机制(Ergonomics)触发的。
- 年轻代信息:[PSYoungGen: 454133K->39886K(454144K)]
- 454133K:年轻代回收前的大小。
- 39886K:年轻代回收后的大小,表示释放了大量内存。
- (454144K):年轻代的最大可用内存。
- 老年代信息:[ParOldGen: 755767K->956022K(1720320K)]
- 755767K:老年代回收前的大小。
- 956022K:老年代回收后的大小,表明在 Full GC 后,老年代的内存使用量增加了。
- (1720320K):老年代的最大可用内存。
- 总堆信息:1209901K->995909K(2174464K)
- 1209901K:总堆在 GC 前的大小。
- 995909K:总堆在 GC 后的大小。
- (2174464K):总堆的最大可用内存。
- Metaspace 信息:[Metaspace: 6166K->6166K(1056768K)]
- 表示 Metaspace 的大小没有变化,仍然是 6166K,最大可用内存为 1056768K。
- GC 耗时:5.1099882 secs
- 表示这次 Full GC 操作的持续时间为 5.1099882 秒。
- 其他信息:[Times: user=43.84 sys=0.11, real=5.11 secs]
- user=43.84:用户 CPU 时间,表示 GC 操作中消耗的用户态 CPU 时间。
- sys=0.11:系统 CPU 时间,表示 GC 操作中消耗的内核态 CPU 时间。
- real=5.11 secs:表示实际的墙钟时间,即从开始到结束的总时间。
- 总结
- 这条日志显示了一次 Full GC,由于内存压力,年轻代释放了大量空间,但老年代的使用量却大幅增加,表明可能有很多对象被晋升到老年代。整个过程持续了约 5 秒,CPU 使用主要集中在用户态。
日志分析工具
- GCViewer
- visual VM
个人感觉后者好用一些: