IDEA jvm 启动调优 参考 深入理解Java虚拟机

最近看了《深入理解Java虚拟机》感触很深,就试着对自己的idea进行调优实践,记录如下:
(第一次在网上发文章,如有不对指出,希望大神指正)

第一步

查看gc日志

添加配置如下:

    # 打印gc

​    -XX:+PrintGC

​    # 打印gc详情

​    -XX:+PrintGCDetails

​    # 打印gc停顿耗时

​    -XX:+PrintGCTimeStamps

​    # 打印gc的时候添加时间标志

​    -XX:+PrintGCDateStamps

​    # 输出位置

​    -Xloggc:/Users/Danny/Documents/java/log/idea/gc.log

日志输出如下:

    2019-03-20T18:34:47.664-0800: 0.335: [GC (Allocation Failure) 2019-03-20T18:34:47.664-0800: 0.335: [ParNew: 34944K->4352K(39296K), 0.0235984 secs] 34944K->9107K(126720K), 0.0237457 secs] [Times: user=0.08 sys=0.02, real=0.02 secs] 

​    2019-03-20T18:34:47.777-0800: 0.448: [GC (Allocation Failure) 2019-03-20T18:34:47.777-0800: 0.448: [ParNew: 39296K->4352K(39296K), 0.0087480 secs] 44051K->12278K(126720K), 0.0088293 secs] [Times: user=0.06 sys=0.00, real=0.01 secs] 

​    2019-03-20T18:34:48.059-0800: 0.729: [GC (Allocation Failure) 2019-03-20T18:34:48.059-0800: 0.730: [ParNew: 39296K->4352K(39296K), 0.0101041 secs] 47222K->16725K(126720K), 0.0102179 secs] [Times: user=0.06 sys=0.00, real=0.01 secs] 

​    2019-03-20T18:34:48.692-0800: 1.363: [GC (Allocation Failure) 2019-03-20T18:34:48.692-0800: 1.363: [ParNew: 39296K->4352K(39296K), 0.0200235 secs] 51669K->26196K(126720K), 0.0201311 secs] [Times: user=0.06 sys=0.01, real=0.02 secs] 

​    2019-03-20T18:34:50.712-0800: 3.383: [GC (CMS Initial Mark) [1 CMS-initial-mark: 21844K(87424K)] 47248K(126720K), 0.0024990 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 

​    2019-03-20T18:34:50.715-0800: 3.386: [CMS-concurrent-mark-start]

​    2019-03-20T18:34:50.725-0800: 3.396: [CMS-concurrent-mark: 0.010/0.010 secs] [Times: user=0.03 sys=0.00, real=0.01 secs] 

​    2019-03-20T18:34:50.725-0800: 3.396: [CMS-concurrent-preclean-start]

​    2019-03-20T18:34:50.726-0800: 3.397: [CMS-concurrent-preclean: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

​    2019-03-20T18:34:50.726-0800: 3.397: [CMS-concurrent-abortable-preclean-start]

​    2019-03-20T18:34:51.149-0800: 3.820: [GC (Allocation Failure) 2019-03-20T18:34:51.149-0800: 3.820: [ParNew: 39296K->4352K(39296K), 0.0135339 secs] 61140K->35671K(126720K), 0.0136103 secs] [Times: user=0.06 sys=0.01, real=0.02 secs] 

​    2019-03-20T18:34:51.404-0800: 4.075: [GC (Allocation Failure) 2019-03-20T18:34:51.404-0800: 4.075: [ParNew: 39296K->4351K(39296K), 0.0064494 secs] 70615K->39107K(126720K), 0.0065322 secs] [Times: user=0.04 sys=0.00, real=0.01 secs] 

​    2019-03-20T18:34:51.411-0800: 4.082: [CMS-concurrent-abortable-preclean: 0.183/0.685 secs] [Times: user=2.43 sys=0.09, real=0.69 secs] 

​    2019-03-20T18:34:51.411-0800: 4.082: [GC (CMS Final Remark) [YG occupancy: 4956 K (39296 K)]2019-03-20T18:34:51.411-0800: 4.082: [Rescan (parallel) , 0.0023462 secs]2019-03-20T18:34:51.414-0800: 4.085: [weak refs processing, 0.0000408 secs]2019-03-20T18:34:51.414-0800: 4.085: [class unloading, 0.0033510 secs]2019-03-20T18:34:51.417-0800: 4.088: [scrub symbol table, 0.0027581 secs]2019-03-20T18:34:51.420-0800: 4.091: [scrub string table, 0.0003787 secs][1 CMS-remark: 34755K(87424K)] 39712K(126720K), 0.0094268 secs] [Times: user=0.03 sys=0.00, real=0.01 secs] 

​    2019-03-20T18:34:51.421-0800: 4.092: [CMS-concurrent-sweep-start]

​    2019-03-20T18:34:51.433-0800: 4.104: [CMS-concurrent-sweep: 0.012/0.012 secs] [Times: user=0.07 sys=0.00, real=0.01 secs] 

​    2019-03-20T18:34:51.433-0800: 4.104: [CMS-concurrent-reset-start]

​    2019-03-20T18:34:51.438-0800: 4.109: [CMS-concurrent-reset: 0.006/0.006 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] 

​    2019-03-20T18:34:51.515-0800: 4.185: [GC (Allocation Failure) 2019-03-20T18:34:51.515-0800: 4.186: [ParNew: 39295K->4029K(39296K), 0.0026156 secs] 69328K->34062K(126720K), 0.0026858 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] 

关于cms的几个阶段可以参考如下

[http://fengfu.io/2016/06/21/JVM-%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E5%99%A8CMS%E4%B9%8B%E5%90%84%E9%98%B6%E6%AE%B5%E6%95%B4%E7%90%86/]

[https://www.cnblogs.com/zhangxiaoguang/p/5792468.html]

​ log里头99%都是GC (Allocation Failure)造成的young gc。Allocation Failure表示向young generation(eden)给新对象申请空间,但是young generation(eden)剩余的合适空间不够所需的大小导致的minor gc。

最后看full gc 的扩容

    2019-03-20T20:36:00.277-0800: 3632.918: [Full GC (System.gc()) 

​    2019-03-20T20:36:00.278-0800: 3632.918: [CMS: 184874K->98447K(289064K), 1.3009498 secs] 200372K->98447K(328360K), [Metaspace: 240354K->240354K(1271808K)], 1.3052543 secs] [Times: user=0.90 sys=0.40, real=1.31 secs] 

​    2019-03-20T20:43:18.915-0800: 4071.564: [GC (Allocation Failure) 2019-03-20T20:43:18.915-0800: 4071.564: [ParNew: 115712K->1768K(130176K), 0.0092860 secs] 214159K->100216K(419240K), 0.0096646 secs] [Times: user=0.06 sys=0.00, real=0.01 secs] 

​    2019-03-20T20:50:39.596-0800: 4512.254: [GC (Allocation Failure) 

​    2019-03-20T20:50:39.681-0800: 4512.339: [ParNew: 117480K->1873K(130176K), 0.0098727 secs] 215928K->100321K(419240K), 0.0955434 secs] [Times: user=0.05 sys=0.01, real=0.10 secs] 

图如下:


Screen Shot 2019-03-22 at 01.41.32.png
Pasted Graphic 3.png

最终确定配置如下

    # eden 113m + from 14.125m + to 14.125m(上图程序自动扩容显示)

​    -Xmn156m

​    # new 150m + old 282.289m

​    -Xms468m

​    -Xmx768m

​    # 283.953 Metaspace扩容时触发FullGC的初始化阈值(默认值FGC的阈值是约20.8m)

​    -XX:MetaspaceSize=300m

​    # Metaspace最大值

​    -XX:MaxMetaspaceSize=300m

调优后效果如下:

Screen Shot 2019-03-21 at 14.03.20.png

​ 还是发生了两次old的gc,按常理内存是够的所以在此查看日志:

16.577: [GC (Allocation Failure) 16.577: [ParNew Desired survivor size 8159232 bytes, new threshold 1 (max 6) - age   1:   11982624 bytes,   11982624 total

: 142742K->15936K(143808K), 0.0211620 secs] 296485K->180210K(463296K), 0.0212467 secs] [Times: user=0.12 sys=0.01, real=0.02 secs] 

16.599: [GC (CMS Initial Mark) [1 CMS-initial-mark: 164274K(319488K)] 180483K(463296K), 0.0188112 secs] [Times: user=0.04 sys=0.00, real=0.02 secs] 

16.618: [CMS-concurrent-mark-start]

16.753: [CMS-concurrent-mark: 0.125/0.135 secs] [Times: user=0.67 sys=0.02, real=0.14 secs] 

16.753: [CMS-concurrent-preclean-start]

16.759: [CMS-concurrent-preclean: 0.005/0.006 secs] [Times: user=0.04 sys=0.00, real=0.00 secs] 

16.759: [CMS-concurrent-abortable-preclean-start]

17.095: [CMS-concurrent-abortable-preclean: 0.324/0.336 secs] [Times: user=1.99 sys=0.08, real=0.34 secs] 

17.096: [GC (CMS Final Remark) [YG occupancy: 83210 K (143808 K)]17.096: [Rescan (parallel) , 0.0317955 secs]17.127: [weak refs processing, 0.0002594 secs][1 CMS-remark: 164274K(319488K)] 247484K(463296K), 0.0321534 secs] [Times: user=0.20 sys=0.01, real=0.03 secs] 

17.128: [CMS-concurrent-sweep-start]

17.312: [CMS-concurrent-sweep: 0.165/0.184 secs] [Times: user=1.11 sys=0.05, real=0.19 secs] 

17.312: [CMS-concurrent-reset-start]

17.338: [CMS-concurrent-reset: 0.023/0.026 secs] [Times: user=0.12 sys=0.01, real=0.02 secs] 

​ 经过分析发现在old空间还有124M不应该发生gc,通过查阅书籍《深入了解java虚拟机》发现CMS有一个浮动垃圾预留空间默认为68%,但是是一个保守估计,现在的技术已经可以提高到92%,所以跳高参数比值如下:

这里分析的有误,后查资料发现java8这个值的默认值为92%,Java8之前的为68%,那为什么还会有FGC呢,这是因为默认值只是第一次使用有效,之后虚拟机会动态调整的,所以这里可以调小点,然后加上XX:+UseCMSInitiatingOccupancyOnly 使其不会改变。

# new 150m + old 282.289m/0.85 = 330 (因为处理浮动垃圾需要预留空间CMSInitiatingOccupancyFraction=85)

-Xms480m

-Xmx480m

# eden 113m + from 14.125m + to 14.125m(上图程序自动扩容显示) 只能使用90%

-Xmn150m

# 如果没有 -XX:+UseCMSInitiatingOccupancyOnly 这个参数, 只有第一次会使用85这个值. 后面的情况会自动调整。 注意这里,java8之前默认值为68%,java8的时候变成了92%

-XX:CMSInitiatingOccupancyFraction=85

-XX:+UseCMSInitiatingOccupancyOnly


效果如下图:

Pasted Graphic 5.png

果然如我所料,FGC一次也没有了,真的是好兴奋。

​ 最后在适当加大new的内存,因为观察gc日志发现每次的回收大小大概20M左右,但是survivor的大小只有15M,所以在此调整所有的空间如下:

# new 150m + old 282.289m/0.85 = 330 (因为处理浮动垃圾需要预留空间CMSInitiatingOccupancyFraction=85)

-Xms500m

-Xmx500m

# eden 113m + from 14.125m + to 14.125m(上图程序自动扩容显示) 只能使用90%

-Xmn200m

# 如果没有 -XX:+UseCMSInitiatingOccupancyOnly 这个参数, 只有第一次会使用85这个值. 后面的情况会自动调整。

-XX:CMSInitiatingOccupancyFraction=85

-XX:+UseCMSInitiatingOccupancyOnly

Pasted Graphic 7.png

​ 效果完美,而且使用的内存最小化的方案,哈哈,可能我平时也是比较抠门吧,对于节省方面达到了斤斤计较的地步了。但是做技术应该有精益求精的精神,在对于微服务方面,上千上万的服务中,每个节省一些空间,最后都是巨大效益。而且空间大不仅浪费空间,而且还会浪费gc的时间。

最终配置如下:

# 设置为服务器模式 使用C2深度编译,虽然编译耗时长,但是后期运行深度优化的代码速度快

# 但是对于一直不关idea的情况,推荐使用

-server

# new 150m + old 282.289m/0.85 = 330 (因为处理浮动垃圾需要预留空间CMSInitiatingOccupancyFraction=85)

-Xms500m

-Xmx500m

# eden 113m + from 14.125m + to 14.125m(上图程序自动扩容显示) 只能使用90%

-Xmn200m

-Xss256k

# 283.953 Metaspace扩容时触发FullGC的初始化阈值(默认值FGC的阈值是约20.8m)

-XX:MetaspaceSize=300m

# Metaspace最大值

-XX:MaxMetaspaceSize=300m

# 关闭System.gc() 

-XX:+DisableExplicitGC

-XX:+UseConcMarkSweepGC

# 设置cms在老年代空间被使用多少百分比之后触发垃圾回收默认68(因为有浮动垃圾)

-XX:CMSInitiatingOccupancyFraction=85

# 如果没有 -XX:+UseCMSInitiatingOccupancyOnly 这个参数, 只有第一次会使用85这个值. 后面的情况会自动调整。

-XX:+UseCMSInitiatingOccupancyOnly

# 节省64位指针占用的空间,代价是JVM额外开销 由ergonomics控制 

-XX:+UseCompressedOops

# 增大软引用在JVM中的存活时长(堆空闲空间越大越久)

-XX:SoftRefLRUPolicyMSPerMB=50

-Dfile.encoding=UTF-8

-ea

-Dsun.io.useCanonCaches=false

-Djava.net.preferIPv4Stack=true

-Djdk.http.auth.tunneling.disabledSchemes=""

-XX:+HeapDumpOnOutOfMemoryError

# 禁止字节码校验

-Xverify:none

# 省略异常栈信息从而快速抛出,JVM对一些特定的异常类型做了FastThrow优化,如果检测到在代码里某个位置连续

# 多次抛出同一类型异常的话,C2会决定用FastThrow方式来抛出异常,而异常Trace即详细的异常栈信息会被清空。

# 这种异常抛出速度非常快,因为不需要在堆里分配内存,也不需要构造完整的异常栈信息。

-XX:-OmitStackTraceInFastThrow



-XX:ErrorFile=$USER_HOME/java_error_in_idea_%p.log

-XX:HeapDumpPath=$USER_HOME/java_error_in_idea.hprof



# 打印gc

-XX:+PrintGC

# 打印gc详情

-XX:+PrintGCDetails

# 打印gc停顿耗时

-XX:+PrintGCTimeStamps

# 输出位置

-Xloggc:/Users/Danny/Documents/java/log/idea/gc.log



# 打印每次的年龄阀值

# -XX:+PrintTenuringDistribution

# 啰嗦的gc信息 上面已经包含了这个参数

# -verbose:gc

# 打印gc的时候添加时间标志

# -XX:+PrintGCDateStamps

# 代码缓存,用于存放Just In Time编译后的本地代码,如果塞满,JVM将只解释执行,不再编译native代码,server 64位的默认值

# -XX:ReservedCodeCacheSize=240m

# 当频繁执行某个方法时,生成字节码来加快反射的执行速度,查看jvm优化陷阱

# 些多态方法调用点的性能反而会显著下降。所以,为了适应多层编译模式,JDK 7里这两个参数的默认值就被改为false了

# -XX:+UseFastAccessorMethods

# 每次永久存储区满了后一般GC算法在做扩展分配内存前都会触发一次FULL GC,除非设置了次选项 感觉没用

# -Xnoclassgc

# 默认开

# -XX:+UseParNewGC

# 设置后发现没有用 虚拟机会自动调节

# -XX:MaxTenuringThreshold=6

# 默认开为了减少第二次暂停的时间,开启并行remark(第三阶段的CMS Remark) 会增加gc总时间

# -XX:+CMSParallelRemarkEnabled

# 默认开当FCC 的时候启用CMS压缩(因为cms会产生碎片,所以要手动压缩参数)

# -XX:+UseCMSCompactAtFullCollection

你可能感兴趣的:(IDEA jvm 启动调优 参考 深入理解Java虚拟机)