jvm-config

用户头像
wkq2786130
关注
发布于: 2020 年 07 月 22 日



原文 http://weikeqin.com/2020/06/09/jvm-config/



java -XX:+PrintFlagsFinal -version | grep HeapSize # 查看堆内存配置的默认值
jmap -heap pid



常用的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 编译。



#CompileThreshold must be between 0 and 268435455
-XX:CompileThreshold=128



方法调用计数器:用于统计方法被调用的次数

方法调用计数器的默认阈值在 C1 模式下是 1500 次,在 C2 模式在是 10000 次,可通过 -XX:CompileThreshold 来设定;而在分层编译的情况下,-XX:CompileThreshold 指定的阈值将失效,此时将会根据当前待编译的方法数以及编译线程数来动态调整。



-XX:OnStackReplacePercentage=10000



回边计数器:用于统计一个方法中循环体代码执行的次数,



在字节码中遇到控制流向后跳转的指令称为“回边”(Back Edge),该值用于计算是否触发 C1 编译的阈值,在不开启分层编译的情况下,C1 默认为 13995,C2 默认为 10700,可通过 -XX: OnStackReplacePercentage=N 来设置;而在分层编译的情况下,-XX: OnStackReplacePercentage 指定的阈值同样会失效,此时将根据当前待编译的方法数以及编译线程数来动态调整。



在一些循环周期比较长的代码段中,当循环达到回边计数器阈值时,JVM 会认为这段是热点代码,JIT 编译器就会将这段代码编译成机器语言并缓存,在该循环时间段内,会直接将执行代码替换,执行缓存的机器语言。



-XX:CICompilerCount=2



经常执行的方法,默认情况下,方法体大小小于 325 字节的都会进行内联,我们可以通过 -XX:MaxFreqInlineSize=N 来设置大小值;

不是经常执行的方法,默认情况下,方法大小小于 35 字节才会进行内联,我们也可以通过 -XX:MaxInlineSize=N 来重置大小值



-XX:+PrintCompilation //在控制台打印编译过程信息
-XX:+UnlockDiagnosticVMOptions //解锁对JVM进行诊断的选项参数。默认是关闭的,开启后支持一些特定参数对JVM进行诊断
-XX:+PrintInlining //将内联方法打印出来



<!--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




| Option and Default Value | 描述 | Description |

| :----- | :----- | :----- |

| -XX:+UseG1GC | 使用G1垃圾收集器 | Use the Garbage First (G1) Collector |

| -XX:MaxGCPauseMillis=200 | 设置G1收集过程目标时间,默认值200ms | Sets a target for the maximum GC pause time. This is a soft goal, and the JVM will make its best effort to achieve it. |

| -XX:InitiatingHeapOccupancyPercent=30 | 设置触发标记周期的 Java 堆占用率阈值。默认值是45%。这里的java堆占比指的是nonyoungcapacity_bytes,包括old+humongous | Percentage of the (entire) heap occupancy to start a concurrent GC cycle. It is used by GCs that trigger a concurrent GC cycle based on the occupancy of the entire heap, not just one of the generations (e.g., G1). A value of 0 denotes 'do constant GC cycles'. The default value is 45. |

| -XX:NewRatio=2 | 新生代 老年代 比例 | Ratio of new/old generation sizes. The default value is 2. |

| -XX:SurvivorRatio=8 | Eden区 Survivor区 比例 | Ratio of eden/survivor space size. The default value is 8. |

| -XX:MaxTenuringThreshold=15 | 新生代最大需要经历多少次GC晋升到老年代。 | Maximum value for tenuring threshold. The default value is 15. |

| -XX:ParallelGCThreads=2 | 设置在垃圾回收器的并行阶段使用的线程数。 | Sets the number of threads used during parallel phases of the garbage collectors. The default value varies with the platform on which the JVM is running. |

| -XX:ConcGCThreads=2 | 并发垃圾收集器将使用的线程数。| Number of threads concurrent garbage collectors will use. The default value varies with the platform on which the JVM is running. |

| -XX:G1ReservePercent=10 | 设置作为空闲空间的预留内存百分比,以降低目标空间溢出的风险 | Sets the amount of heap that is reserved as a false ceiling to reduce the possibility of promotion failure. The default value is 10. |

| -XX:G1HeapRegionSize=25 | 设置Region大小 | With G1 the Java heap is subdivided into uniformly sized regions. This sets the size of the individual sub-divisions. The default value of this parameter is determined ergonomically based upon heap size. The minimum value is 1Mb and the maximum value is 32Mb. |




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 //关闭偏向锁
-XX:+UseHeavyMonitors //设置重量级锁
-XX:-UseSpinning //参数关闭自旋锁优化(默认打开)
-XX:PreBlockSpin //参数修改默认的自旋次数。JDK1.7后,去掉此参数,由jvm控制



-XX:-UseBiasedLocking 关闭偏向锁



在高并发场景下,当大量线程同时竞争同一个锁资源时,偏向锁就会被撤销,发生 stop the word 后, 开启偏向锁会带来更大的性能开销



-XX:-RestrictContended



避免伪共享

多线程并发条件下,volite变量导致CPU缓存里的数据和主内存的数据不一致导致CPU缓存失效。



-XX:-RestrictContended

避免伪共享是以牺牲内存为代价的



伪共享和 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)是判断一个对象是否被外部方法引用或外部线程访问的分析技术,编译器会根据逃逸分析的结果对代码进行优化。



-XX:+DoEscapeAnalysis //开启逃逸分析(jdk1.8默认开启)
-XX:-DoEscapeAnalysis //关闭逃逸分析



标量替换

逃逸分析证明一个对象不会被外部访问,如果这个对象可以被拆分的话,当程序真正执行的时候可能不创建这个对象,而直接创建它的成员变量来代替。将对象拆分后,可以分配对象的成员变量在栈或寄存器上,原本的对象就无需分配内存空间了。这种编译优化就叫做标量替换。



public void foo() {
TestInfo info = new TestInfo();
info.id = 1;
info.count = 99;
...//to do something
}



public void foo() {
id = 1;
count = 99;
...//to do something
}



-XX:+EliminateLocks //开启锁消除(jdk1.8默认开启)
-XX:-EliminateLocks //关闭锁消除
-XX:+EliminateAllocations //开启标量替换(jdk1.8默认开启)
-XX:-EliminateAllocations //关闭标量替换

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同步锁的优化方法



发布于: 2020 年 07 月 22 日 阅读数: 24
用户头像

wkq2786130

关注

hello 2018.09.28 加入

http://weikeqin.com/

评论

发布
暂无评论
jvm-config