jvm-config
原文 http://weikeqin.com/2020/06/09/jvm-config/
常用的JVM配置
-Dfile.encoding=UTF-8
文件使用UTF-8编码
-Xms2g
设置初始堆大小为2G
-Xmx2g
设置最大堆大小为1G
-Xmn1g
设置新生代大小为1G
-Xss256k
设置每个线程的堆栈大小,和栈的深度和容器创建的最大线程数有关
-XX:LargePageSizeInBytes=128m
内存页的大小不可设置过大, 会影响Perm的大小
-XX:MaxDirectMemorySize=536870912
-XX:+UseFastAccessorMethods
原始类型的快速优化
-XX:PetenureSizeThreshold=
设置直接被分配到老年代的最大阀值
-XX:+TraceClassLoading
打印类加载信息
gc日志信息
-XX:+PrintGC
用于垃圾收集时的信息打印 -verbosegc (which is equivalent to -XX:+PrintGC) sets the detail level of the log to fine.
-XX:+PrintGCDetails
打印GC详细信息 ets the detail level to finer.
-XX:+PrintGCTimeStamps
输出GC的时间戳(以基准时间的形式 245469.1 )
-XX:+PrintGCDateStamps
输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
-XX:+HeapDumpBeforeFullGC
FullGC前保存堆栈信息 测试环境使用,线上最好别用,小心磁盘被打满
-XX:+HeapDumpAfterFullGC
FullGC后保存堆栈信息 测试环境使用,线上最好别用,小心磁盘被打满
-XX:+DisableExplicitGC
禁止代码中显示调用GC
-Xloggc:filename
gc日志保存到指定文件 把filename替换成 /home/admin/gc.log
-XX:+HeapDumpOnOutOfMemoryError
OOM后保存堆栈信息
-XX:-OmitStackTraceInFastThrow
当大量抛出同样的异常的后,后面的异常输出将不打印堆栈
-XX:ErrorFile=logs/hs_err_pid%p.log
JIT config
JVM 的 JIT 机制的存在,如果某个函数被调用多次之后,JVM会尝试将其编译为机器码,从而提高执行速度。
在 Java8 之前,HotSpot 集成了两个 JIT,用 C1 和 C2 来完成 JVM 中的即时编译。
到了 Java9,AOT 编译器被引入。AOT 是在程序运行前进行的静态编译,这样就可以避免运行时的编译消耗和内存消耗,且 .class 文件通过 AOT 编译器是可以编译成 .so 的二进制文件的。
Java10,一个新的 JIT 编译器 Graal 被引入。Graal 是一个以 Java 为主要编程语言、面向 Java bytecode 的编译器。与用 C++ 实现的 C1 和 C2 相比,它的模块化更加明显,也更容易维护。Graal 既可以作为动态编译器,在运行时编译热点方法;也可以作为静态编译器,实现 AOT 编译。
方法调用计数器:用于统计方法被调用的次数
方法调用计数器的默认阈值在 C1 模式下是 1500 次,在 C2 模式在是 10000 次,可通过 -XX:CompileThreshold 来设定;而在分层编译的情况下,-XX:CompileThreshold 指定的阈值将失效,此时将会根据当前待编译的方法数以及编译线程数来动态调整。
回边计数器:用于统计一个方法中循环体代码执行的次数,
在字节码中遇到控制流向后跳转的指令称为“回边”(Back Edge),该值用于计算是否触发 C1 编译的阈值,在不开启分层编译的情况下,C1 默认为 13995,C2 默认为 10700,可通过 -XX: OnStackReplacePercentage=N 来设置;而在分层编译的情况下,-XX: OnStackReplacePercentage 指定的阈值同样会失效,此时将根据当前待编译的方法数以及编译线程数来动态调整。
在一些循环周期比较长的代码段中,当循环达到回边计数器阈值时,JVM 会认为这段是热点代码,JIT 编译器就会将这段代码编译成机器语言并缓存,在该循环时间段内,会直接将执行代码替换,执行缓存的机器语言。
经常执行的方法,默认情况下,方法体大小小于 325 字节的都会进行内联,我们可以通过 -XX:MaxFreqInlineSize=N 来设置大小值;
不是经常执行的方法,默认情况下,方法大小小于 35 字节才会进行内联,我们也可以通过 -XX:MaxInlineSize=N 来重置大小值
<!--more-->
CMS垃圾回收器配置
Eden --|
Survior0 Space ---- Young Generation
Survior1 Space --|
Old Generation
Permanent Generation
-XX:+UseConcMarkSweepGC
使用CMS垃圾收集器
-XX:+CMSParallelRemarkEnabled
降低标记停顿
-XX:CMSFullGCsBeforeCompaction=*
-XX:+UseCMSCompactAtFullCollection
在FullGC的时候 对年老代的压缩
-XX:CMSInitiatingOccupancyFraction=75
CMS垃圾收集会在老年代被占用75%时被触发
-XX:+UseCMSInitiatingOccupancyOnly
基于运行时收集的数据来启动CMS垃圾收集周期
G1垃圾收集器配置
Ende Space
Survivor Space
Oid Generation
G1 Log
-verbosegc
(which is equivalent to -XX:+PrintGC) sets the detail level of the log to fine.
-XX:+PrintGCDetails
sets the detail level to finer.
-XX:+UnlockExperimentalVMOptions -XX:G1LogLevel=finest
sets the detail level to its finest. Like finer but includes individual worker thread information.
-XX:+PrintGCTimeStamps
Shows the elapsed time since the JVM started.
-XX:+PrintGCDateStamps
Adds a time of day prefix to each entry.
Lock config
-XX:-UseBiasedLocking
关闭偏向锁
在高并发场景下,当大量线程同时竞争同一个锁资源时,偏向锁就会被撤销,发生 stop the word 后, 开启偏向锁会带来更大的性能开销
-XX:-RestrictContended
避免伪共享
多线程并发条件下,volite变量导致CPU缓存里的数据和主内存的数据不一致导致CPU缓存失效。
避免伪共享是以牺牲内存为代价的
伪共享和 CPU 内部的 Cache 有关,Cache 内部是按照缓存行(Cache Line)管理的,缓存行的大小通常是 64 个字节;CPU 从内存中加载数据 X,会同时加载 X 后面(64-size(X))个字节的数据。
避免伪共享很简单,每个变量x独占一个缓存行、不共享缓存行就可以了,具体技术是缓存行填充。
比如想让 变量x 独占一个缓存行,可以在 变量x 的前后各填充 64-size(x) 个字节,这样就一定能保证 变量x 独占一个缓存行。
由于伪共享问题如此重要,所以 Java 也开始重视它了,比如 Java 8 中,提供了避免伪共享的注解:@sun.misc.Contended,通过这个注解就能轻松避免伪共享(需要设置 JVM 参数 -XX:-RestrictContended)。不过避免伪共享是以牺牲内存为代价的
40 | 案例分析(三):高性能队列Disruptor
逃逸分析
逃逸分析(Escape Analysis)是判断一个对象是否被外部方法引用或外部线程访问的分析技术,编译器会根据逃逸分析的结果对代码进行优化。
标量替换
逃逸分析证明一个对象不会被外部访问,如果这个对象可以被拆分的话,当程序真正执行的时候可能不创建这个对象,而直接创建它的成员变量来代替。将对象拆分后,可以分配对象的成员变量在栈或寄存器上,原本的对象就无需分配内存空间了。这种编译优化就叫做标量替换。
References
[1] Chapter 4 Tuning the Java Runtime System
[2] 关键系统的JVM参数推荐(2018仲夏版)
[3] github.com/alibaba/arthas
[4] github.com/vipshop/vjtools
[5] JVM诊断调优CheatSheet
[6] understanding-jit-compiler-just-in-time-compiler
[7] Java Hotspot G1 GC的一些关键技术
[8] Getting Started with the G1 Garbage Collector
[9] java
[10] should-heapdumpbeforefullgc-be-used-in-production-environment
[11] JVM实用参数(七)CMS收集器
[12]12 | 多线程之锁优化(上):深入了解Synchronized同步锁的优化方法
版权声明: 本文为 InfoQ 作者【wkq2786130】的原创文章。
原文链接:【http://xie.infoq.cn/article/21d5d4fe7182aeaefcfedff81】。文章转载请联系作者。
评论