前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >记录一次maven JVM 调优

记录一次maven JVM 调优

作者头像
全栈程序员站长
发布2022-08-27 18:12:39
5800
发布2022-08-27 18:12:39
举报
文章被收录于专栏:全栈程序员必看

大家好,又见面了,我是你们的朋友全栈君。

记录一次maven JVM 调优

前言

  • 记录一次无(摸)聊(鱼)的GC 调优过程,本着学以致用、务实求真的精神,看了《深入理解Java虚拟机》中作者对自己的开发ide eclipse 工具做了JVM 调优,觉得很有意思。感觉这个确实是可以用自己的知识来提升开发效率,所以就有了这次的玄学调优之旅,文中如果有错误,希望能够指出,非常感谢。

优化背景

  • 我本人目前有个工作上的项目,编译的时间大概需要30多秒,这次的目标就是从JVM的层面折腾、优化编译速度,那么就开始吧

编译时间基准线

  1. 优化前的编译时间,先跑个基准时间作为参考:
代码语言:javascript
复制
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  35.901 s
[INFO] Finished at: 2020-12-14T13:37:31+08:00
[INFO] ------------------------------------------------------------------------

第一次尝试,配置相关JVM 参数

  1. 调优前的准备,打印 JVM 运行时的配置,这里配置的参数可以打印 JVM 的相关运行时的 gc 详情,用来观察虚拟机的运行状态
  • XX:+PrintVMOptions 打印外部的传入的vm参数
  • XX:+PrintGCDetails 打印发生在垃圾收集的时候,gc详情日志
  • XX:+PrintCommandLineFlags 这里可以打印出:隐式或者显示传递给虚拟机的参数输出。这里的隐式其实算是非用户传入的参数,算是jvm自己填充的参数,可以把具体的相关运行参数被打印出来。
  • 本次JVM传入的参数: export MAVEN_OPTS=" -XX:+PrintVMOptions -XX:+PrintGCDetails -XX:+PrintCommandLineFlags"
  1. 执行 mvn clean ,尝试将JVM 运行时的参数打印出
代码语言:javascript
复制
VM option '+PrintVMOptions'
VM option '+PrintCommandLineFlags'
VM option '+PrintGCDetails'
-XX:InitialHeapSize=268435456 -XX:MaxHeapSize=4294967296 -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+PrintVMOptions -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
[GC (Allocation Failure) [PSYoungGen: 65536K->9718K(76288K)] 65536K->9734K(251392K), 0.0062610 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
.
.
.
.
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.431 s
[INFO] Finished at: 2020-12-14T13:59:18+08:00
[INFO] ------------------------------------------------------------------------
Heap
 PSYoungGen      total 76288K, used 75254K [0x000000076ab00000, 0x0000000770000000, 0x00000007c0000000)
  eden space 65536K, 100% used [0x000000076ab00000,0x000000076eb00000,0x000000076eb00000)
  from space 10752K, 90% used [0x000000076eb00000,0x000000076f47dbc8,0x000000076f580000)
  to   space 10752K, 0% used [0x000000076f580000,0x000000076f580000,0x0000000770000000)
 ParOldGen       total 175104K, used 16K [0x00000006c0000000, 0x00000006cab00000, 0x000000076ab00000)
  object space 175104K, 0% used [0x00000006c0000000,0x00000006c0004000,0x00000006cab00000)
 Metaspace       used 16058K, capacity 16450K, committed 16640K, reserved 1064960K
  class space    used 1931K, capacity 2025K, committed 2048K, reserved 1048576K

第一次内存分析

  • 可以看到这里的默认堆大小是:76288K, 年轻代的大小为:74m ,老年代 171m。可以看到在mvn编译启动的时候便立即发生了一次minor gc([PSYoungGen: 65536K->9718K(76288K)]),是初始化的堆太小了,将项目完整编译一遍,试试看堆会扩容到多大,执行 mvn clean install。编译的结果如下:编译的耗时为38s,堆的大小从开始的76288K 扩容到 1287168K,所以第一个优化点就是将默认堆的大小调大,减少扩容堆带来的时间损耗,调大年轻代的大小为1GB
  • 最终的 JVM 参数调整为:
  • 本次JVM传入的参数:export MAVEN_OPTS="-XX:+PrintHeapAtGC -Xmn1024m -Xms2048m -Xmx2048m -XX:+PrintVMOptions -XX:+PrintCommandLineFlags -XX:+PrintGCDetails"

调整堆大小,进行第二次尝试

代码语言:javascript
复制
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  38.060 s
[INFO] Finished at: 2020-12-14T15:19:05+08:00
[INFO] ------------------------------------------------------------------------
Heap
 PSYoungGen      total 1287168K, used 389414K [0x000000076ab00000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 1209344K, 25% used [0x000000076ab00000,0x000000077db49bd8,0x00000007b4800000)
  from space 77824K, 99% used [0x00000007bb400000,0x00000007bffffdc8,0x00000007c0000000)
  to   space 94208K, 0% used [0x00000007b4800000,0x00000007b4800000,0x00000007ba400000)
 ParOldGen       total 290304K, used 110998K [0x00000006c0000000, 0x00000006d1b80000, 0x000000076ab00000)
  object space 290304K, 38% used [0x00000006c0000000,0x00000006c6c65960,0x00000006d1b80000)
 Metaspace       used 57894K, capacity 62322K, committed 62592K, reserved 1103872K
  class space    used 6382K, capacity 7172K, committed 7296K, reserved 1048576K

第二次内存分析

  • 遗憾的发现,我们的时间不仅没有减少,反而还增加了。观察gc日志,我发现虽然没有了堆的扩容,但是却产生了很多的minor gc,还有少许metaspace的full gc,这里我就怀疑是不是年轻代的大小太大,导致的GC。于是我尝试将 -Xmn1024m 参数删除,进行第三次测试,将JVM参数调整为:
  • 本次JVM传入的参数::export MAVEN_OPTS="-XX:+PrintHeapAtGC -Xms2048m -Xmx2048m -XX:+PrintVMOptions -XX:+PrintCommandLineFlags -XX:+PrintGCDetails"

第三次尝试

代码语言:javascript
复制
VM option '+PrintVMOptions'
VM option '+PrintCommandLineFlags'
VM option '+PrintGCDetails'
-XX:InitialHeapSize=2147483648 -XX:MaxHeapSize=2147483648 -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+PrintVMOptions -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
.
.
.
.
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  35.620 s
[INFO] Finished at: 2020-12-14T15:26:05+08:00
[INFO] ------------------------------------------------------------------------
Heap
 PSYoungGen      total 553472K, used 114468K [0x0000000795580000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 424448K, 3% used [0x0000000795580000,0x0000000796247788,0x00000007af400000)
  from space 129024K, 78% used [0x00000007b8200000,0x00000007be501928,0x00000007c0000000)
  to   space 137216K, 0% used [0x00000007af400000,0x00000007af400000,0x00000007b7a00000)
 ParOldGen       total 1398272K, used 145292K [0x0000000740000000, 0x0000000795580000, 0x0000000795580000)
  object space 1398272K, 10% used [0x0000000740000000,0x0000000748de3158,0x0000000795580000)
 Metaspace       used 57842K, capacity 62194K, committed 62336K, reserved 1103872K
  class space    used 6383K, capacity 7172K, committed 7296K, reserved 1048576K

第三次日志分析

  • 尝试移除掉了负优化之后(捂脸,大约 快了3s左右的时间。这里可以看到年轻代的大小有所调整,大概在500MB,而且整个编译速度有所提升。为了仔细的观察gc 的情况,不至于看着混乱,于是我将gc 的日志输入到一个文件中-Xloggc:./gc.log,下面贴出完整的gc 日志打印:
代码语言:javascript
复制
Java HotSpot(TM) 64-Bit Server VM (25.271-b09) for bsd-amd64 JRE (1.8.0_271-b09), built on Sep 16 2020 16:54:38 by "java_re" with gcc 4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.11.45.5)
Memory: 4k page, physical 16777216k(184620k free)

/proc/meminfo:

CommandLine flags: -XX:InitialHeapSize=2147483648 -XX:MaxHeapSize=2147483648 -XX:+PrintCommandLineFlags -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintVMOptions -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC 
3.140: [GC (Metadata GC Threshold) [PSYoungGen: 493352K->37959K(611840K)] 493352K->37991K(2010112K), 0.0324232 secs] [Times: user=0.16 sys=0.03, real=0.04 secs] 
3.173: [Full GC (Metadata GC Threshold) [PSYoungGen: 37959K->0K(611840K)] [ParOldGen: 32K->37023K(1398272K)] 37991K->37023K(2010112K), [Metaspace: 20506K->20506K(1069056K)], 0.0630022 secs] [Times: user=0.40 sys=0.03, real=0.06 secs] 
4.939: [GC (Metadata GC Threshold) [PSYoungGen: 265335K->17127K(611840K)] 302359K->54230K(2010112K), 0.0162070 secs] [Times: user=0.10 sys=0.01, real=0.02 secs] 
4.956: [Full GC (Metadata GC Threshold) [PSYoungGen: 17127K->0K(611840K)] [ParOldGen: 37103K->40811K(1398272K)] 54230K->40811K(2010112K), [Metaspace: 34039K->34039K(1081344K)], 0.0567554 secs] [Times: user=0.47 sys=0.01, real=0.06 secs] 
7.199: [GC (Allocation Failure) [PSYoungGen: 524800K->30799K(611840K)] 565611K->71618K(2010112K), 0.0206191 secs] [Times: user=0.09 sys=0.00, real=0.02 secs] 
10.369: [GC (Allocation Failure) [PSYoungGen: 555599K->46401K(611840K)] 596418K->87263K(2010112K), 0.0353684 secs] [Times: user=0.18 sys=0.05, real=0.04 secs] 
12.176: [GC (Allocation Failure) [PSYoungGen: 571201K->58712K(611840K)] 612063K->99582K(2010112K), 0.0341386 secs] [Times: user=0.18 sys=0.02, real=0.03 secs] 
13.351: [GC (Allocation Failure) [PSYoungGen: 583512K->66532K(591360K)] 624382K->123804K(1989632K), 0.0805149 secs] [Times: user=0.29 sys=0.09, real=0.08 secs] 
15.009: [GC (Metadata GC Threshold) [PSYoungGen: 447655K->76668K(601600K)] 504928K->133948K(1999872K), 0.0391952 secs] [Times: user=0.30 sys=0.03, real=0.04 secs] 
15.048: [Full GC (Metadata GC Threshold) [PSYoungGen: 76668K->0K(601600K)] [ParOldGen: 57280K->86590K(1398272K)] 133948K->86590K(1999872K), [Metaspace: 55127K->55067K(1101824K)], 0.2553197 secs] [Times: user=1.80 sys=0.02, real=0.26 secs] 
17.057: [GC (Allocation Failure) [PSYoungGen: 524800K->18698K(601088K)] 611390K->105296K(1999360K), 0.0201318 secs] [Times: user=0.07 sys=0.02, real=0.02 secs] 
18.214: [GC (Allocation Failure) [PSYoungGen: 523018K->22484K(601600K)] 609616K->109090K(1999872K), 0.0158255 secs] [Times: user=0.09 sys=0.01, real=0.01 secs] 
19.663: [GC (Allocation Failure) [PSYoungGen: 526804K->27010K(605184K)] 613410K->113625K(2003456K), 0.0122234 secs] [Times: user=0.09 sys=0.00, real=0.01 secs] 
20.413: [GC (Allocation Failure) [PSYoungGen: 535938K->27130K(602624K)] 622553K->113753K(2000896K), 0.0092859 secs] [Times: user=0.07 sys=0.00, real=0.01 secs] 
22.083: [GC (Allocation Failure) [PSYoungGen: 536058K->35399K(611840K)] 622681K->122029K(2010112K), 0.0127960 secs] [Times: user=0.07 sys=0.00, real=0.01 secs] 
23.143: [GC (Allocation Failure) [PSYoungGen: 556103K->44218K(607744K)] 642733K->130857K(2006016K), 0.0121441 secs] [Times: user=0.09 sys=0.00, real=0.01 secs] 
24.467: [GC (Allocation Failure) [PSYoungGen: 564922K->43628K(617984K)] 651561K->130274K(2016256K), 0.0150819 secs] [Times: user=0.12 sys=0.00, real=0.02 secs] 
25.041: [GC (Allocation Failure) [PSYoungGen: 577644K->50829K(614912K)] 664290K->137483K(2013184K), 0.0171980 secs] [Times: user=0.12 sys=0.00, real=0.02 secs] 
26.725: [GC (Allocation Failure) [PSYoungGen: 584845K->49607K(619520K)] 671499K->136269K(2017792K), 0.0143381 secs] [Times: user=0.09 sys=0.00, real=0.01 secs] 
27.863: [GC (Allocation Failure) [PSYoungGen: 588743K->49783K(618496K)] 675405K->136453K(2016768K), 0.0204793 secs] [Times: user=0.14 sys=0.00, real=0.02 secs] 
29.283: [GC (Allocation Failure) [PSYoungGen: 588919K->78840K(596480K)] 675589K->171466K(1994752K), 0.0301864 secs] [Times: user=0.24 sys=0.00, real=0.03 secs] 
32.061: [GC (Allocation Failure) [PSYoungGen: 596472K->90602K(608256K)] 689098K->203223K(2006528K), 0.0488591 secs] [Times: user=0.31 sys=0.03, real=0.06 secs] 
33.521: [GC (Allocation Failure) [PSYoungGen: 608234K->90605K(547840K)] 720855K->211839K(1946112K), 0.0405590 secs] [Times: user=0.26 sys=0.01, real=0.04 secs] 
34.908: [GC (Allocation Failure) [PSYoungGen: 547821K->88780K(546304K)] 669055K->224085K(1944576K), 0.0416360 secs] [Times: user=0.35 sys=0.02, real=0.04 secs] 
Heap
 PSYoungGen      total 546304K, used 535026K [0x0000000795580000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 457216K, 97% used [0x0000000795580000,0x00000007b0949748,0x00000007b1400000)
  from space 89088K, 99% used [0x00000007b1400000,0x00000007b6ab3298,0x00000007b6b00000)
  to   space 125952K, 0% used [0x00000007b8500000,0x00000007b8500000,0x00000007c0000000)
 ParOldGen       total 1398272K, used 135304K [0x0000000740000000, 0x0000000795580000, 0x0000000795580000)
  object space 1398272K, 9% used [0x0000000740000000,0x00000007484223f8,0x0000000795580000)
 Metaspace       used 57880K, capacity 62258K, committed 62592K, reserved 1103872K
  class space    used 6387K, capacity 7172K, committed 7296K, reserved 1048576K
  • 从GC 日志可以看到 metaspace 的容量太小,导致几次full gc ,这里我们调整永久代 metaspace 的大小,老年代的使用率同样也不高,所以添加 JVM 参数:-XX:MetaspaceSize=256m,再来一次:
  • 本次JVM传入的参数:export MAVEN_OPTS="-XX:+UseParallelGC -XX:+UseParallelOldGC -Xloggc:./gc.log -Xmn1024m -XX:+PrintHeapAtGC -XX:MetaspaceSize=256m -Xms2048m -Xmx2048m -XX:+PrintVMOptions -XX:+PrintCommandLineFlags -XX:+PrintGCDetails"

第四次尝试

代码语言:javascript
复制
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  36.261 s
[INFO] Finished at: 2020-12-14T16:16:55+08:00
[INFO] ------------------------------------------------------------------------

第四次分析

  • 这次调整之后,虽然没有产生一次full gc ,但是却产生了很多次的minor gc,时间没有降低,可以确定了是由于年轻代的空间设置的比较大,对象的来回复制同样也是非常耗时的。于是确定的将 -Xmn1024m移除,使用默认的比例。考虑 JVM 有自适应大小内存策略,每次 GC 后会重新计算 Eden、From 和 To 区的大小。于是加上了 -XX:-UseAdaptiveSizePolicy做一次尝试,继续重跑。
  • 本次JVM传入的参数:export MAVEN_OPTS="-XX:+UseParallelGC -XX:+UseParallelOldGC -Xloggc:./gc.log -XX:+PrintHeapAtGC -XX:MetaspaceSize=256m -XX:-UseAdaptiveSizePolicy -Xms2048m -Xmx2048m -XX:+PrintVMOptions -XX:+PrintCommandLineFlags -XX:+PrintGCDetails"

第五次尝试

代码语言:javascript
复制
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  34.900 s
[INFO] Finished at: 2020-12-14T16:40:07+08:00
[INFO] ------------------------------------------------------------------------

第五次分析:

  • 一共产生了20次的minor gc,0次full gc。这次终于跑进了 34 秒大关。成功玄学的优化了1秒钟

G1

试一试G1吧!

  • 接下来我们来试试G1-GC的垃圾回收器表现的性能如何,将原本的 JVM GC参数删除,配置为G1的GC 回收:
  • 本次JVM传入的参数:export MAVEN_OPTS="-XX:+UseG1GC"
代码语言:javascript
复制
.
.
.
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  43.946 s
[INFO] Finished at: 2020-12-14T23:41:30+08:00
[INFO] ------------------------------------------------------------------------
  • 很遗憾,G1并不适用于这种偏向吞吐量任务型的作业,折腾之旅此就为止,谢谢观看。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/146682.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年5月1,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 记录一次maven JVM 调优
    • 前言
      • 优化背景
        • 编译时间基准线
        • 第一次尝试,配置相关JVM 参数
        • 第一次内存分析
        • 调整堆大小,进行第二次尝试
        • 第二次内存分析
        • 第三次尝试
        • 第三次日志分析
        • 第四次尝试
        • 第四次分析
        • 第五次尝试
        • 第五次分析:
      • G1
        • 试一试G1吧!
    相关产品与服务
    Elasticsearch Service
    腾讯云 Elasticsearch Service(ES)是云端全托管海量数据检索分析服务,拥有高性能自研内核,集成X-Pack。ES 支持通过自治索引、存算分离、集群巡检等特性轻松管理集群,也支持免运维、自动弹性、按需使用的 Serverless 模式。使用 ES 您可以高效构建信息检索、日志分析、运维监控等服务,它独特的向量检索还可助您构建基于语义、图像的AI深度应用。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档