jvm优化

为什么需要对JVM优化

  • 运行的程序卡住了,日志不输出,程序没有反应

  • 服务器负载突然升高

  • 在多线程应用下,如何合理分配线程数量

JVM运行参数

JVM的参数分为三类:

  • 标准参数(不会发生变化)

    • -help

    • -version

  • -X参数(非标准参数,可能会发生变化)

    • -Xint

    • -Xcomp

  • -XX参数(使用率较高,多用于JVM调优)

    • -XX:newSize

    • -XX:+UseSerialGC

标准参数

jvm的标准参数,一般都很稳定,在未来的JVM版本中不会改变,可以使用 java -help检索出所有的标准参数。

C:\Users\Feathers>java -help
用法: java [options] <主类> [args...]
           (执行类)
     java [options] -jar <jar 文件> [args...]
           (执行 jar 文件)
     java [options] -m <模块>[/<主类>] [args...]
       java [options] --module <模块>[/<主类>] [args...]
           (执行模块中的主类)

 将主类, -jar <jar >, -m  --module
 <模块>/<主类> 后的参数作为参数传递到主类。

 其中, 选项包括:

    -cp <目录和 zip/jar 文件的类搜索路>
    -classpath <目录和 zip/jar 文件的类搜索路>
    --class-path <目录和 zip/jar 文件的类搜索路>
                  使用 ; 分隔的, 用于搜索类文件的目录, JAR 档案
                   ZIP 档案列表。
    -p <模块路>
    --module-path <模块路>...
                   ; 分隔的目录列表, 每个目录
                  都是一个包含模块的目录。
    --upgrade-module-path <模块路>...
                   ; 分隔的目录列表, 每个目录
                  都是一个包含模块的目录, 这些模块
                  用于替换运行时映像中的可升级模块
    --add-modules <模块名>[,<模块名>...]
                  除了初始模块之外要解析的根模块。
                  <模块名称> 还可以为 ALL-DEFAULT, ALL-SYSTEM,
                  ALL-MODULE-PATH.
    --list-modules
                  列出可观察模块并退出
    -d <module name>
    --describe-module <模块名>
                  描述模块并退出
    --dry-run     创建 VM 并加载主类, 但不执行 main 方法。
                   --dry-run 选项对于验证诸如
                  模块系统配置这样的命令行选项可能非常有用。
    --validate-modules
                  验证所有模块并退出
                  --validate-modules 选项对于查找
                  模块路径中模块的冲突及其他错误可能非常有用。
    -D<名称>=<值>
                  设置系统属性
    -verbose:[class|module|gc|jni]
                  启用详细输出
    -version      将产品版本输出到错误流并退出
    --version     将产品版本输出到输出流并退出
    -showversion  将产品版本输出到错误流并继续
    --show-version
                  将产品版本输出到输出流并继续
    --show-module-resolution
                  在启动过程中显示模块解析输出
    -? -h -help
                  将此帮助消息输出到错误流
    --help        将此帮助消息输出到输出流
    -X            将额外选项的帮助输出到错误流
    --help-extra  将额外选项的帮助输出到输出流
    -ea[:<程序包名称>...|:<类名>]
    -enableassertions[:<程序包名称>...|:<类名>]
                  按指定的粒度启用断言
    -da[:<程序包名称>...|:<类名>]
    -disableassertions[:<程序包名称>...|:<类名>]
                  按指定的粒度禁用断言
    -esa | -enablesystemassertions
                  启用系统断言
    -dsa | -disablesystemassertions
                  禁用系统断言
    -agentlib:<库名>[=<选项>]
                  加载本机代理库 <>, 例如 -agentlib:jdwp
                  另请参阅 -agentlib:jdwp=help
    -agentpath:<路径名>[=<选项>]
                  按完整路径名加载本机代理库
    -javaagent:<jar >[=<>]
                  加载 Java 编程语言代理, 请参阅 java.lang.instrument
    -splash:<图像路径>
                  使用指定的图像显示启动屏幕
                  自动支持和使用 HiDPI 缩放图像
                  (如果可用)。应始终将未缩放的图像文件名 (例如, image.ext)
                  作为参数传递给 -splash 选项。
                  将自动选取提供的最合适的缩放
                  图像。
                  有关详细信息, 请参阅 SplashScreen API 文档
    @argument 文件
                  一个或多个包含选项的参数文件
    -disable-@files
                  阻止进一步扩展参数文件
要为长选项指定参数, 可以使用 --<名称>=<> 
--<名称> <>

-version 与 -showversion

使用-version查看JDK的版本

C:\Users\Feathers>java -version
# jdk版本
java version "10.0.1" 2018-04-17 
Java(TM) SE Runtime Environment 18.3 (build 10.0.1+10) 
# jvm HotSpot 版本
Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10.0.1+10, mixed mode) 

# 如果想要在Java程序运行后查看JVM的版本信息,可以使用 -showversion
# 因为jvm的一些信息和配置是可以修改的,以此进行调试
java -showversion Test

C:\Users\Feathers>java -client -showversion Test
java version "10.0.1" 2018-04-17
Java(TM) SE Runtime Environment 18.3 (build 10.0.1+10)
Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10.0.1+10, mixed mode)
hello world

-D 设置main方法参数

可以使用-D为Java设置系统属性,可以在使用 System.getProperty("参数名称")获取:

public static void main(String[] args) {

    String test = System.getProperty("test");
    if (test == null) {
        System.out.println("test is null");
    } else {
        System.out.println("test is " + test);
    }
}
// 使用命令 javac Test.java 编译 
// java -Dtest=hello
// 结果:test is hello

注意,-D参数是JVM运行参数,指定的是系统属性,要区别Program Arguments,main方法参数。

-server 和 -client

可以通过-server-client设置jvm的模式:

  • Server VM的初始空间会大一些,默认使用并行垃圾回收器,启动慢运行快

  • Client VM 相对保守,初始化空间比较小,使用串行垃圾回收器,目标是让JVM启动速度更快,但是运行速度会比Server VM慢一些

  • JVM在启动时会根据硬件和操作系统自动选择Server还是Client类型的JVM

    • 32位Windows系统,无论硬件如何,都会默认使用Client VM

    • 其他操作系统中,2G以上并且拥有2个CPU,将会默认使用 Server VM

    • 如果是64位操作系统,只会使用Server VM,不支持Client VM

测试

# 指定以ClientVM方式运行,本机当前位win64、16核cpu、16g内存的配置
java -Dtest=hello -showversion -client

# 发现JVM仍然以Server VM的方式运行程序
java version "1.8.0_112"
Java(TM) SE Runtime Environment (build 1.8.0_112-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.112-b15, mixed mode)

test is hello

-X 非标准参数

查看所有非标准参数

C:\Users\Feathers>java -X

    -Xbatch           禁用后台编译
    -Xbootclasspath/a:<以 ; 分隔的目录和 zip/jar >
                      附加在引导类路径末尾
    -Xcheck:jni        JNI 函数执行其他检查
    -Xcomp            在首次调用时强制编译方法
    -Xdebug           为实现向后兼容而提供
    -Xdiag            显示附加诊断消息
    -Xfuture          启用最严格的检查, 预期将来的默认值
    -Xint             仅解释模式执行
    -Xinternalversion
                      显示比 -version 选项更详细的 JVM
                      版本信息
    -Xloggc:<file>     GC 状态记录在文件中 (带时间戳)
    -Xmixed           混合模式执行 (默认值)
    -Xmn<size>        为年轻代 (新生代) 设置初始和最大堆大小
                      (以字节为单位)
    -Xms<size>        设置初始 Java 堆大小
    -Xmx<size>        设置最大 Java 堆大小
    -Xnoclassgc       禁用类垃圾收集
    -Xrs              减少 Java/VM 对操作系统信号的使用 (请参阅文档)
    -Xshare:auto      在可能的情况下使用共享类数据 (默认值)
    -Xshare:off       不尝试使用共享类数据
    -Xshare:on        要求使用共享类数据, 否则将失败。
    -XshowSettings    显示所有设置并继续
    -XshowSettings:all
                      显示所有设置并继续
    -XshowSettings:locale
                      显示所有与区域设置相关的设置并继续
    -XshowSettings:properties
                      显示所有属性设置并继续
    -XshowSettings:vm 显示所有与 vm 相关的设置并继续
    -Xss<size>        设置 Java 线程堆栈大小
    -Xverify          设置字节码验证器的模式
    --add-reads <>=<目标模>(,<目标模块>)*
                      更新 <> 以读取 <目标模>, 而无论
                      模块声明如何。
                      <目标模块> 可以是 ALL-UNNAMED 以读取所有未命名
                      模块。
    --add-exports <>/<程序>=<目标模>(,<目标模块>)*
                      更新 <> 以将 <程序> 导出到 <目标模>,
                      而无论模块声明如何。
                      <目标模块> 可以是 ALL-UNNAMED 以导出到所有
                      未命名模块。
    --add-opens <>/<程序>=<目标模>(,<目标模块>)*
                      更新 <> 以在 <目标模> 中打开
                      <程序包>, 而无论模块声明如何。
    --illegal-access=<>
                      允许或拒绝通过未命名模块中的代码对命名模块中的
                      类型成员进行访问。
                      <>  "deny", "permit", "warn"  "debug" 之一
                      此选项将在未来发行版中删除。
    --limit-modules <模块>[,<模块>...]
                      限制可观察模块的领域
    --patch-module <>=<>(;<文件>)*
                      使用 JAR 文件或目录中的类和资源
                      覆盖或增强模块。
    --disable-@files 禁止进一步扩展参数文件

这些额外选项如有更改, 恕不另行通知。

-Xint、-Xcomp、-Xmixed

-Xint-Xcomp-Xmixed用于指定JVM的运行模式:

  • -Xint:解释模式(interpreted mode),会强制JVM执行所有的字节码,这回降低运行速度,通常低10倍或者更多

  • -Xcomp:会将所有字节码编译为本地代码,再去执行,从而得到最大程序优化。但是编译时间会很长

  • -Xmixed: 是混合模式,将解释模式与编译模式进行混合使用,由jvm自己决定,这是 jvm默认的模式,也是推荐使用的模式

示例

# 默认是 mixed mode
[root@node01 test]# java -showversion  Test
java version "1.8.0_141"
Java(TM) SE Runtime Environment (build 1.8.0_141-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.141-b15, mixed mode) # 看这里

# 指定 -Xint模式
[root@node01 test]# java -Xint -showversion  Test
java version "1.8.0_141"
Java(TM) SE Runtime Environment (build 1.8.0_141-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.141-b15, interpreted mode)

# 指定 -Xcomp 模式(运行之前有明显的卡顿)
[root@node01 test]# java -Xcomp  -showversion  Test
java version "1.8.0_141"
Java(TM) SE Runtime Environment (build 1.8.0_141-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.141-b15, compiled mode)

# 指定 -Xmixed 模式
[root@node01 test]# java -Xmixed -showversion  Test
java version "1.8.0_141"
Java(TM) SE Runtime Environment (build 1.8.0_141-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.141-b15, mixed mode)

-XX非标准参数(常用于JVM调优)

-XX参数也是非标准参数,主要用于JVM调优与Debug操作。他的参数值的指定有两种形式:

  • boolean 形式

    -XX:[+-]<name> 表示启用(+)或者禁用(-)name属性
    例如:
    -XX:+DisableExplicitGC 表示禁用手动调用gc的操作,即System.gc()
  • 非boolean形式

    -XX:<name>=<value> 表示name属性的值<value>
    -XX:NewRatio=1 表示新生代和老年代的比值

示例:

java ‐showversion ‐XX:+DisableExplicitGC Test
java version "1.8.0_141" Java(TM) SE Runtime Environment (build 1.8.0_141‐b15) Java HotSpot(TM) 64‐Bit Server VM (build 25.141‐b15, mixed mode)

查看所有的-XX参数

C:\Users\Feathers>java -XX:+PrintFlagsFinal  -version
[Global flags]
bool 	AggressiveHeap 			= false 	{product} 		{default}
int 	ActiveProcessorCount	= -1 		{product} 		{default}
intx 	AutoBoxCacheMax			= 128		{C2 product}	{default}
uintx 	CMSOldPLABNumRefills	= 4			{product} 		{default}
ccstr 	AllocateHeapAt			=			{product} 		{default}
size_t 	CMSOldPLABMax			= 1024		{product} 		{default}
ccstrlist CompileOnly  			= 			{product} 		{default}
bool ZeroTLAB					= false	{product} 			{default}
# .. 这里太多,请自行查看
###########
# 其中 
# 第一列代表参数值的类型,bool代表bool型,其他代表非bool型
# 第二列代表参数名称
# 第三列中 =右边代表参数值,在1.8中,被修改的属性以:=表示
# 第四列 暂时不清楚 todo 
# 第五列代表参数使用的是默认值还是程序赋予的值,defualt:默认值,ergonomic:修改值

查看正在运行的JVM参数

需要借助jinfo命令查看:

# jinfo语法
jinfo -flags <进程id>

# 查看所有的java进程:jps -l
C:\Users\Feathers> jps -l
10960 org.jetbrains.jps.cmdline.Launcher # IDEA
16052
2020 jdk.jcmd/sun.tools.jps.Jps # jps命令本身
16824 org.jetbrains.idea.maven.server.RemoteMavenServe # IDEA maven

# 查看IDEA的JVM参数
C:\Users\Feathers>jinfo -flags 10960
-XX:CICompilerCount=4 -XX:ErrorFile=C:\Users\Feathers\java_error_in_idea_%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=C:\Users\Feathers\java_error_in_idea.hprof -XX:InitialHeapSize=536870912 -XX:MaxHeapSize=2147483648 -XX:MaxNewSize=715784192 -XX:MaxTenuringThreshold=6 -XX:MinHeapDeltaBytes=196608 -XX:NewSize=178913280 -XX:NonNMethodCodeHeapSize=5835340 -XX:NonProfiledCodeHeapSize=122911450 -XX:OldSize=357957632 -XX:-OmitStackTraceInFastThrow -XX:ProfiledCodeHeapSize=122911450 -XX:ReservedCodeCacheSize=251658240 -XX:+SegmentedCodeCache -XX:SoftRefLRUPolicyMSPerMB=50 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:-UseLargePagesIndividualAllocation
# 可以看到我的IDEA MaxHeapSize 为2147483648 大约2g InitialHeapSize 大约512m

# 参数太多,如何查看指定参数
C:\Users\Feathers>jinfo -flag MaxHeapSize 10960
-XX:MaxHeapSize=2147483648

-Xms 与 -Xmx

-Xms-Xmx是属于-XX参数的,虽然他只有一个-X,他们只是 -XX:InitialHeapSize-XX:MaxHeapSize 的缩写。

  • -Xms用于指定JVM堆的初始大小,比如-Xms512m,等价于-XX:InitialHeapSize=512m堆空间的初始大小为512M

  • -Xmx则用于指定JVM堆的最大堆内存大小,比如-Xmx2048m,等价于-XX:MaxHeapSize=2048M对空间的最大大小为2G

调整JVM内存大小,可以充分利用服务器资源,让程序跑的更快。

示例:

java -Xms512m -Xmx2048m Test
Hello World!!!

jstat监测统计堆内存

jstat命令可以查看堆内存各部分的使用量,以及加载类的数量。命令的格式如下:

jstat [-命令选项] [vmid] [间隔时间/毫秒] [查询次数] 

class加载统计

C:\Users\Feathers>jps
11012 Jps
4392
9672 Launcher
11964 RemoteMavenServer

C:\Users\Feathers>jstat -class 4392
Loaded  Bytes  Unloaded  Bytes     Time
 50872 106971.7       33    30.1      97.04

说明:

  • Loaded:加载class的数量

  • Bytes:所占用空间大小

  • Unloaded:未加载数量

  • Bytes:未加载占用空间

  • Time:时间

编译统计

C:\Users\Feathers>jstat -compiler  4392
Compiled Failed Invalid   Time   FailedType FailedMethod
   22972      2       0    74.86          1 java/lang/ClassLoader defineClass

说明:

  • Compiled:编译数量。

  • Failed:失败数量

  • Invalid:不可用数量

  • Time:时间

  • FailedType:失败类型

  • FailedMethod:失败的方法

垃圾回收统计

C:\Users\Feathers>jstat -gc  4392
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
17472.0 17472.0 14586.3  0.0   139776.0 23202.7   349568.0   203657.4  312112.0 299154.6 45288.0 40400.4     14    0.248   0      0.000    0.248

# 实时监控
# 每隔一秒钟,打印一次gc状态,共打印5次
C:\Users\Feathers>jstat -gc  4392 1000 5
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
17472.0 17472.0 14586.3  0.0   139776.0 24413.4   349568.0   203657.4  312112.0 299154.6 45288.0 40400.4     14    0.248   0      0.000    0.248
17472.0 17472.0 14586.3  0.0   139776.0 24580.4   349568.0   203657.4  312112.0 299154.6 45288.0 40400.4     14    0.248   0      0.000    0.248
17472.0 17472.0 14586.3  0.0   139776.0 24580.4   349568.0   203657.4  312112.0 299154.6 45288.0 40400.4     14    0.248   0      0.000    0.248
17472.0 17472.0 14586.3  0.0   139776.0 24692.4   349568.0   203657.4  312112.0 299154.6 45288.0 40400.4     14    0.248   0      0.000    0.248
17472.0 17472.0 14586.3  0.0   139776.0 24722.0   349568.0   203657.4  312112.0 299154.6 45288.0 40400.4     14    0.248   0      0.000    0.248

说明:

  • S0C:第一个Survivor区的大小(KB)

  • S1C:第二个Survivor区的大小(KB)

  • S0U:第一个Survivor区的使用大小(KB)

  • S1U:第二个Survivor区的使用大小(KB)

  • EC:Eden区的大小(KB)

  • EU:Eden区的使用大小(KB)

  • OC:Old区大小(KB)

  • OU:Old使用大小(KB)

  • MC:方法区大小(KB)

  • MU:方法区使用大小(KB)

  • CCSC:压缩类空间大小(KB)

  • CCSU:压缩类空间使用大小(KB)

  • YGC:年轻代垃圾回收次数

  • YGCT:年轻代垃圾回收消耗时间

  • FGC:老年代垃圾回收次数

  • FGCT:老年代垃圾回收消耗时间

  • GCT:垃圾回收消耗总时间

jmap详细监测统计堆内存

jstat命令可以对jvm堆内存进行统计分析,而jmap可以获取到更加详细的内容。

最后更新于