目录

Java Hotspot JVM参数详解

Java Hotspot JVM参数详解

本文只针对JDK7以及之前版本的HotSpot参数说明。

本文提供说明了影响jvm性能的命令行参数和环境变量,除非特别说明,否则所有的信息适用于JVM的client模式与server模式

JVM虚拟机参数分为几类,以-X开头的参数是非标准参数,不保证所有的VM实现都支持这种参数,可能在后续版本的JDK中发生变化,不会另行通知

以-XX开头的参数是不稳定参数,可能会随时变化,不另行通知。

标准参数

-client -server

从J2SE5.0版本开始,当程序启动时,启动器会检查程序是否在server模式下运行,根据上面两个参数选择使用Java HotSpot Server VM还是Java HotSpot Client VM。目的是为了提升性能。通常来看,server VM比client VM启动慢,但是启动后运行更快。

在Java SE 6中,server-class定义为至少2核CPU和2GB的物理内存的机器

Java SE6中,如果启动时没有指定-server或者-client参数,在i586或者Sparc 32结构运行Solaris或者Linux的机器上默认进行server-class检测,如果符合server-class的要求,使用server模式,否则使用client模式。i586的windows平台机器上默认使用client模式,Sun支持的平台上只能使用server模式。

平台架构 操作系统 默认client模式 如果服务器server-class,server模式,否则client模式 默认server模式
SPARC 32-bit Solaris X
i586 Solaris X
i586 Linux X
i586 Microsoft Windows X
SPARC 64-bit Solaris - X
AMD64 Solaris - X
AMD64 Linux - X
AMD64 Microsoft Windows - X

从表中可以看出,64位的jdk已经不支持client模式,64位的JDK现在已经忽略-client的参数,直接使用Java Hotspot Server模式

-agentlib:libname[=options] -agentpath:pathname[=options]

加载本地库libname,如进行性能监控时

主要在使用JVMTI(JVM Tool Interface)对JVM运行状态进行监控等时使用,JVMTI是开发监控工具时使用的一组程序接口。它提供了控制与监控JVM运行状态的能力。JVMTI可以开发分析,监控,线程分析,覆盖率分析等工具。

JVMTI不是所有的JVM都会实现。

-agentlib与-agentpath都是加载JVMTI agent的参数,不同的是一个是从系统LD_LIBARAY_PATH中查找库文件(-agentlib),这种查找方式跟链接时使用的-l库方式一样,查找lib[libname].so, 在windows下为libname.dll,而-agentpath中是指定具体的路径进行查找加载。

这里介绍一个jdk自带的JVMTI工具,hprof,用于性能分析优化调测时使用,可以使用 java -agentlib:hprof=help查看该库的具体使用方法,主要参数列表在帮助中写的比较详细,使用方式如: java -agentlib:hprof=cpu=samples, interval=100, depth=4,file=/home/agent/java.hprof.txt,将CPU使用的信息记入到java.hprof.txt文件中,运行后可以通过文件查看,存储方式默认为文本格式,可以使用二进制方式生成二进制文件,然后使用工具打开进行解析查看

-classpath -cp

设置classpath,一堆目录的列表,jvm运行时会到相关目录下查找jar文件与zip文件,各个目录使用:分割,可以理解为库文件地址,类似与LD_LIBRARY_PATH参数的含义,如果没有设置,默认为当前路径(.)。

-Dproperty=value

设置一个自定义的系统参数,在系统运行时可以使用System.getProperty()获得设置的值

-d32 -d64

用来指定程序运行在32位还是64位环境,如果系统不支持相应环境,会报错。默认情况下应用会运行在32位环境下除非系统只能支持64bit。当前只有server VM支持64位操作,-server参数跟-d64参数是冲突的。如果同时指定-client跟-d64,-client参数会被忽略。该参数很可能会在后续版本中修改

-disableassertions[:package name”…” | :class name]

-da[:package name”…” | :class name]

-enableassertions[:package name”…” | :class name ]

-ea[:package name”…” | :class name ]

开启/关闭断言。系统默认关闭断言的。

没有参数时,会开启/关闭所有类的断言功能。如果携带的参数以”…“结尾,这个开关会开启/关闭这个包下以及所有子包类的断言,如果参数只有”…",会开启/关闭当前目录下所有未命名包的断言,如果参数结尾没有”…", 则开关只会限定指定的类。

如: 执行程序对com.wombat.fruitbat包开启断言,但是对com.wombat.fruitbat.Brickbat类禁用断言,则命令为:

java -ea:com.wombat.fruibat... -da:com.wombat.fruitbat.Brickbat <Main Class>

注意: 上面几个参数对所有的类加载器与系统类都有效。但是有一个例外: 在没有参数的情况下,开关对系统类不生效。这样就可以对所有除系统类以外的类打开断言。系统类断言的打开关闭可以使用下面几个参数。

-enablesystemassertions

-esa

**-**disablesystemassertions

-dsa

开启/关闭系统类的断言

-javaagent

加载Java编写的代理,主要基于java.lang.instrument进行编写的代理程序,Instrumentation主要为JVM运行时提供测量手段,可以编写工具通过Instrumentation修改字节码,收集数据等,启动JVM时指定agent类,Instrumentation实例通过premain方法传入。通过这种方式可以进行系统分析,监控,覆盖率分析等功能。

在版本搜索中包括/排除用户专有JRE

所谓用户专有JRE,就是系统中可能会安装多个JRE,JRE只是一个配置文件,需要的lib库文件跟其他扩展文件等组合。比如你在安装jdk的时候回安装一个私有JRE,安装过程中也可以选择它是否成为共有JRE,私有JRE是执行JDK工具所必须的,但是他没有注册配置,只有被JDK使用,换言之,共有JRE因为已经向系统注册如windows的注册表,所以会被所有的java程序,浏览器等使用。

-verbose

**-**verbose:class

-verbose:gc

**-**verbose:jni

显示类加载/垃圾回收/jni调用的详细信息。如,我们在做程序时发现ClassNotFoundException等,我们怀疑可能jar包或者类没有被全部加载,所以可以使用verbose:class查看所有类的加载情况,具体看看是否有类加载的遗失。同样,如果我们verbose:gc也是一个调测中比较常用的参数,我们可以通过该参数打印系统垃圾回收的详细信息,有助于帮助我们定位内存使用以及垃圾回收的各种问题

还有其他的参数如-help -jar -version等常用简单参数就不一一在这里介绍了

非标准参数

-X

展示所有非标准选项信息,类似于help命令

-Xint

JVM只在解释模式下执行。字节码不会编译成本地代码,所有的字节码在解释模式下运行,这种模式下JVM的JIT编译等性能提升特性不会起作用

-Xbatch

禁用后台编译,正常情况下JVM以后台任务的方式编译方法,在后台编译结束前一直使用解释的方式运行代码。这个参数禁用后台编译,所有的方法都会在前台任务的形式编译

-Xbootclasspath:bootclasspath

-Xbootclasspath/p:path

-Xbootclasspath/a:path

指定以冒号:分个的目录列表(在windows下可能是;),JVM会搜索这些目录下的jar包跟zip文件用来替换JDK的一些启动类,这个参数允许修改来定制核心class如java.lang里的一些类。/a置于引导类路径末尾,/p置于引导类路径之前,如果不带这两个参数则只会从定制的路径里加载,而不会到jdk默认的jre/lib等目录下加载核心类库。注意:JRE二进制license不允许定制覆盖rt.jar里的类

-Xcheck:jni

对jni调用进行附加检查。特别是JVM会检查传给JNI函数的参数,对参数进行校验。任何无效的数据可能会引起本地代码的问题,在这种情况下JVM会抛出一个fatal error。启用这个参数会引起一定的性能下降。

这个参数在定位使用JNI的程序问题时非常有用,有时候本地代码中的bug可能会引起HotSpot VM崩溃。当检查到一个无效参数,JVM会在标准输入输出中打印一条信息,打印出问题的线程的stacktrace,然后结束掉JVM。比如检查null值被错误的传到一个不允许为null的JNI函数参数里,或者JNI函数传参类型错误,使用错误的线程,使用无效的jni引用等问题。

-Xfuture

执行严格的class文件格式检查。为保持向上兼容,JVM后续版本执行的默认的格式检查比早期版本1.1.x等要放松,该选项严格要求class文件格式检查。开发者在开发新代码时建议使用这个参数来严格class校验,因为在java的后续版本中这个可能成为默认值

-Xnoclassgc

禁用对永久区类加载的垃圾回收。使用这个参数可以防止类被重复卸载加载引起的性能损失,但是在一些代理或者osgi等类不断加载的程序中可能会引起内存溢出,出现Permgen OutofmemoryError的错误。

-Xincgc

开启增量垃圾回收。增量垃圾回收器默认是关闭的,增量回收可以减少程序运行过程中偶尔会出现的长时间gc停顿。增量垃圾回收偶尔会与程序共同运行,在于程序一起运行时会占用一定的cpu,影响吞吐量

-Xloggc:file

上报每一次的垃圾回收时间,跟-verbose:gc差不多,但是会记录数据到文件中。除了-verbose:gc的内容之外,-Xloggc每次上报的时间是与第一次gc的时间间隔,单位是s。我们通常可以使用一个本地文件存储gc的信息。当这个选项与-verbose:gc 同时在命令行中指定时,-verboise:gc会被覆盖。

-Xmnsize or -XX:NewSize

设置新生代的大小

-Xms[n]

设置堆内存的初始大小,不带单位时以字节为单位,必须为1024的倍数大于1M,也可以带k K m M单位,这个值的默认值跟底层系统配置有关。从J2SE5.0开始,默认初始化值是机器物理内存的1/64和合理的最小值两个值的最大值,J2SE5.0之前该值就是一个合理的最小值,所谓合理的最小值,是跟平台相关的值。建议还是使用该参数统一进行设置

-Xmx[n]

设置堆内存的最大值,不带单位时以字节为单位,必须为1024的倍数大于2M,跟-Xms一样也可以带参数。默认值跟地层系统配置有关。在J2SE5之前,默认值为64MB,之后默认值为min(1/4的物理内存, 1GB)

-Xprof

分析程序运行情况,打印分析信息到标准输出上,这个选项在软件开发过程中是非常有用的工具,但是不要再生产环境上使用

-Xrs

减少Java/JVM对操作系统信号的使用。在早期版本中,Java程序的关闭提供了回调。这让早期的用户可以在程序关闭甚至是意外关闭时可以清理自己的资源如关闭数据库连接等。JMV通过SIGHUP,SIGINT,和SIGTERM等操作系统信号来实现关闭的回调。JVM也使用SIGQUIT信号实现了dump线程堆栈信息用于调测使用。使用JVM的应用程序经常需要使用SIGINT或者SIGTERM等信号,但是这些信号会被JVM的信号处理器拦截。所以提供-Xrs参数来解决这个问题。当这个参数使用时,SIGINTSIGTERMSIGHUPSIGQUIT等信号不会JVM改变。

使用这个参数会有两个影响:

SIGQUIT dump线程堆栈功能将不可用

用户代码需要响应关闭命令,如调用System.exit()来退出程序

-Xss[n]

设置线程栈大小,在Java SE 6中,在Sparc平台上,32为JVM默认大小是512K,64为JVM默认大小为1024K,在x86的Solaris/Linux上,32位的jvm默认大小是320K,64位的JVM默认大小是1024K。在windows平台上,默认的线程栈大小是从二进制文件java.exe中读取的,对于Java SE 6来说 ,32位JVM默认大小320K,64位JVM默认大小是1024K

-Xverify:mode

设置字节码校验器模式。字节码校验保证class文件的格式正确,符合class文件格式限制。不要关闭校验,因为关闭校验会降低java提供的保护能力,可能会引起问题。可能使用到的mode参数如下:

remote: 检查所有不是bootstrap类加载器加载的类字节码,这是默认参数

all : 校验所有的类字节码

none: 禁用所有字节校验。这个参数在Hotspot JVM中是不支持的。

不稳定参数

在JVM的参数中,以-XX开头的参数是不稳定参数,可能会随时发生变化,不会另行通知。

对于值是Boolean类型的参数打开使用-XX:+<option> 关闭使用-XX:-<option>

对于数字类型的参数可以使用-XX:<option>=<number>来设置,可以携带m M表示MB,k,K 表示KB,g G表示GB

字符串类型的参数可以使用-XX:<option>=<string>来设置,通常会指定一个文件,路径,或者一组命令

下面介绍的参数可以以下几组:

行为参数: 会改变JVM基本行为的参数

G1垃圾回收参数: Garbage First(G1)垃圾回收参数

性能调优参数:性能优化时可能会使用到的参数

调测参数: 通常用来跟踪,打印输出JVM的相关信息

行为参数

参数与默认值 参数描述
-XX:-AllowUserSignalHandlers                               允许用户安装信号处理器(对Solaris与Linux有效)
-XX:AltStackSize=16384 备用信号栈大小,单位KB(只对Solaris有效,从5.0版本后已经删除)
-XX:-DisableExplicitGC 默认情况下允许程序调用System.gc()来做垃圾回收,使用-XX:+DisableExplicitGC来禁止调用System.gc()
-XX:+FailOverToOldVerifier Java6引入的选项,默认开启,使用新的Class校验器校验失败后,使用老的校验器进行校验,Java6引入
-XX:+HandlePromotionFailure 关闭新生代收集担保。java5之前默认关闭。所谓新生代担保,就是在minor gc时,Eden区域Survivor From区的活跃对象会被复制到Survivor To区,但是Survivor To区不一定能够容纳所有活跃对象,如果没有足够空间,则会将相关活跃对象移动到老年代,所以老年代中需要提供额外的内存做担保,正常情况下应该是Eden区大小+一个Survivor区大小,如果老年代没有足够空间,则会发生担保失败,触发一次full gc(1.4.2 update 11引入)
-XX:+MaxFDLimit 设置文件句柄数为系统最大(只对Solaris有效)
-XX:PreBlockSpin=10 前置参数-XX:+UseSpinning java6默认开启,设置多线程自旋锁最大自旋次数,默认为10 1.4.2版本引入
-XX:-RelaxAccessControlCheck 发送class校验器对访问控制的检查。 java6版本引入
-XX:+ScavengeBeforeFullGC full gc前先进行一次新生代的gc。1.4.1版本引入
-XX:+UseAltSigs 使用替代信号代替SIGUSR1和SIGUSR2。1.3.1 update 9引入
-XX:+UseBoundThreads 绑定所有用户线程与内核线程。减少线程得不到CPU时间的可能
-XX:-UseConcMarkSweepGC 使用CMS垃圾回收器进行老年代垃圾回收
-XX:+UseGCOverheadLimit 限制JVM时间使用在GC上的比例,如果超过就抛出OutOfMemory异常。java 6引入
-XX:+UseLWPSynchronization 使用轻量级进程(内核线程)代替线程同步(1.4.0版本引入,只与Solaris有关)
-XX:-UseParallelGC 新生代使用Parallel GC收集器,老年代使用Parallel Scavenges收集器(1.4.1版本引入)
-XX:-UseParallelOldGC 老年代使用Parallel Old垃圾回收器(5.0update6 版本引入)
-XX:-UseSerialGC 使用Serial垃圾回收器(5.0版本引入)
-XX:-UseSpinning 启用多线程自旋锁。线程进入互斥区之前,通过CAS自旋一定次数检测所的释放,如果超过自旋次数再挂起线程。java6默认开启,1.4.2跟5.0版本需要手动启用
-XX:+UseTLAB 使用线程本地缓存,1.4.2与之前版本client模式下关闭,其他情况默认开启。1.4.0版本引入
-XX:+UseSplitVerifier 5.0版本引入,5.0版本默认false,其他默认true。使用Class类型校验器。将老的校验步骤拆分为两步: 1 类型推断。2类型校验。新类型校验器通过javac编译时嵌入类型信息到字节码中,省略了类型推断,提升加载器的性能。
-XX:+UseThreadPriorities 默认启用,使用本地线程优先级
-XX:+UseVMInterruptibleIO java6引入,限solaris系统,允许运行时IO操作等中断线程。

G1垃圾回收器参数

参数与默认值 参数描述
-XX:+UseG1GC 使用G1垃圾回收器
-XX:MaxGCPauseMillis=n 设置最大目标GC停顿时间。这只是个目标,JVM会尽最大的努力达成
-XX:InitiatingHeapOccupancyPercent=n 整个堆占用比例达到n时,开始一个并行的GC周期,这个比例是指整个堆的比例,不是特指某一代。设置为0表示持续做GC周期。默认值是45
-XX:NewRatio=n old/new比例,默认值2
-XX:SurvivorRatio=n eden/survior比例,默认值8,这里指单个Survivor区,survivor有两个
-XX:MaxTenuringThreshold=n 设置垃圾最大存活阈值,控制对象经理多少次Minor GC才能晋升到老年代。默认值是15。如果设置0,年轻带不经过Survivor直接接入老年代。
-XX:ParallelGCThreads=n 设置并行收集的线程数。默认值跟JVM运行的平台有关
-XX:ConcGCThreads=n 同步收集的线程个数,默认值跟JVM运行的平台有关
-XX:G1ReservePercent=n G1回收器预留防止担保失败的内存块个数。默认是10
-XX:G1HeapRegionSize=n G1回收器将内存划分为大小同意的区块。设置每个区块的大小。默认按照堆大小自动设置。最小1Mb, 最大32Mb

性能调优参数

参数与默认值 参数描述
-XX:+AggressiveOpts                               5.0 update 6引入。java 1.6后默认开启,打开编译器性能优化。后续版本可能直接作为默认值
-XX:CompileThreshold=10000 JIT编译的触发阈值。调用多少次会进行JIT编译。client模式默认是1500, server模式下默认1000
-XX:LargePageSizeInBytes=4m 设置java堆内存分页最大页大小。1.4.0 update 1 引入。AMD64位下默认值为2M
-XX:MaxHeapFreeRatio=70 GC后空闲堆内存占到整个预估上限的70%,则收缩预估上限值。JVM启动时,会申请最大值-Xmx的内存地址空间(虚拟内存),但是其中大部分不会立即分配。运行过程中,JVM发现实现使用接近分配上限值,才分配另外一部分内存。已分配上限值也可以叫做预估上限值。
-XX:MaxNewSize=size 新生代的最大值
-XX:MaxPermSize=64m 永久带最大值。(5.0版本以后 64位JVM增大30%。1.4 amd64: 96m, 1.3.1 client模式:32m)
-XX:MinHeapFreeRatio=40 gc后堆内存不足预估上限值的40%,增加上限值
-XX:NewRatio=2 old/new 比例
-XX:NewSize=2m 新生代默认大小
-XX:ReservedCodeCacheSize=32m 预留代码缓存最大值,运行时编译使用
-XX:SurvivorRatio=8 eden/survior比例,默认值8,这里指单个Survivor区,survivor有两个
-XX:TargetSurvivorRatio=50 一个计算周期内期望存活的占用空间占比。根据这个数据与XX:MaxTenuringThreshold JVM计算一个合适的需要转移到老年代的周期岁数。
-XX:ThreadStackSize=512 线程栈大小,与-Xss有冲突。
-XX:+UseBiasedLocking 开启偏向锁。1.5 update 6后引入,默认关闭,java 6后默认启用
-XX:+UseFastAccessorMethods 优化原始类型getter性能
-XX:-UseISM 开启Solaris系统的ISM,非Solaris平台不可用
-XX:+UseLargePages 使用大页内存
-XX:+UseMPSS 启用Solaris系统的MPSS,只在Solaris 9以上版本使用
-XX:+UseStringCache 缓存常用字符串
-XX:AllocatePrefetchLines=1 在使用JIT生成预读取指令分配对象后读取的缓存行数,如果上次分配的对象是一个实例默认值是1,如果是一个数组则是3
-XX:AllocatePrefetchStyle=1 预读取指令的生成代码风格 0-无预读取指令生成 1-每次分配后执行预读取指令 2- 当预读取指令执行后使用TLAB()分配水印指针来找回入口
-XX:+UseCompressedStrings 对于标准ASCII字符,使用byte[]而非char[], 可以节省内存,但是速度较慢(Java 6 Update 21 引入)
-XX:+OptimizeStringConcat Java 6 Update 20引入,在可能的情况下优化字符串连接操作

调测参数

参数与默认值 参数描述
-XX:-CITime 1.4.0引入。打印JIT编译消耗的时间
-XX:ErrorFile=./hs_err_pid<pid>.log Java6 引入。如果错误发生,打印错误数据到文件中
-XX:-ExtendedDTraceProbes 启动dtrace诊断,只对solaris系统
-XX:HeapDumpPath=./java_pid<pid>.hprof 堆内存 快照存储路径,当OOM或者crash时被OS强制终止后会产生一个hprof格式的快照文件,用于问题定位
-XX:-HeapDumpOnOutOfMemoryError 发生OOM时输出内存快照
-XX:OnError="<cmd args>;<cmd args>" JVM抛出ERROR时执行命令行指令集如sh或者bat
-XX:OnOutOfMemoryError="<cmd args>; <cmd args>" 到OOM时执行命令行指令集
-XX:-PrintClassHistogram 在Ctrl+Break或者Linux下kill -3发送SIGQUIT信号时,打印class柱状图。jmap -histo功能类似
-XX:-PrintConcurrentLocks thread dump时,打印java.util.concurrent的锁状态。jstack -l pid也实现同样的功能
-XX:-PrintCommandLineFlags 启动时打印命令行中出现的jvm option参数
-XX:-PrintCompilation 当方法被JIT编译时打印信息
-XX:-PrintGC 开启GC日志打印
-XX:-PrintGCDetails 打印GC回收的详细信息
-XX:-PrintGCTimeStamps 打印GC停顿耗时
-XX:-PrintTenuringDistribution 打印对象存活期限信息
-XX:-PrintAdaptiveSizePolicy 在UseAdaptiveSizePolicy时GC会动态调整eden,to区大小,打开该开关会跟踪每次的变化情况
-XX:-TraceClassLoading 打印class状态信息到stdout
-XX:-TraceClassLoadingPreorder 按照class的引用/依赖顺序打印装载信息到stdout
-XX:-TraceClassResolution 跟踪打印常量池使用
-XX:-TraceClassUnloading 跟踪打印类卸载情况
-XX:-TraceLoaderConstraints 打印class的装载策略变化信息
-XX:+PerfDataSaveToFile 在程序异常退出时保存jvm状态二进制数据
-XX:ParallelGCThreads=n 设置新生代和老年代parallel垃圾回收器的线程数量。默认值跟JVM运行的系统有关
-XX:+UseCompressedOops 设置是否使用压缩指针(使用32位代替64位的指针地址)。对于优化堆内存低于32G的64位JVM性能时使用。
-XX:+AlwaysPreTouch 为了避免运行时性能损失,启动应用时访问并置零所有的内存页面,而不是在程序运行时内存新增时做这个操作
-XX:AllocatePrefetchDistance=n 设置对象分配的预读取距离。
-XX:InlineSmallCode=n 当编译的代码小于指定的值时,内联编译的代码。默认值跟JVM的运行平台有关
-XX:MaxInlineSize=35 内联方法的最大字节数
-XX:FreqInlineSize=n 内联频繁执行的方法最大字节码大小、默认值取决于JVM运行平台有关
-XX:LoopUnrollLimit=n 当server编译器中间节点数小于该值时,展开整个循环体。用于循环展开优化。
-XX:InitialTenuringThreshold=7 对象被移到老年代的年龄阈值的初始值
-XX:MaxTenuringThreshold=n 对象被移到老年代的年龄阈值的最大值,最大15,。parallel 回收器默认值为15, CMS回收器默认值为4
-XX:-UseGCLogFileRotation 开启GC日志文件切分
-XX:NumberOfGClogFiles=1 设置切分GC日志文件数量
-XX:GCLogFileSize=8K 设置GC日志文件切分大小