原文链接 JVM Options Cheat Sheet
欢迎来到 第十个 RebelLabs 备忘单!这次我们将专注于那些你想用但是忽略掉的 JVM 选项。在这篇文章中,我们将介绍每个重要选项的功能。但是首先,让我们回顾一下下面10份备忘录,就要追溯到2015年12月份了!
我艹,太吊了(Wow, what a colorful journey! Here’s an amazing fact for you)。如果打印出上面所有的备忘录放在手边,那么你将腾出很多时间去做你喜欢的事。废话少说,点击下面的图片,打印出来吧,这样你就不用把那些该死的选项记在脑子里了。
让我们从上往下看。有三种类型的选项可以传递给 JVM:标准、非标准和高级选项。
- 如果使用高级选项,需要以
-XX:开头;
- 使用非标准选项则是
-X;
- 标准选项不需要追加任何东西。
我这样来告诉你,是不是发现好记了很多呢!下面,我们就从标准选项开始吧。
标准选项
如果你想获得所有的标准选项列表,只要在命令行输入 java 即可,不需要携带任何参数,你想看到大量的标准选型并且带有使用说明。在这份备忘单中,我们选了一些最有趣的选项。
这里附上我在执行 java 时的输出:
$ java
用法: java [-options] class [args...]
(执行类)
或 java [-options] -jar jarfile [args...]
(执行 jar 文件)
其中选项包括:
-d32 使用 32 位数据模型 (如果可用)
-d64 使用 64 位数据模型 (如果可用)
-server 选择 "server" VM
默认 VM 是 server,
因为您是在服务器类计算机上运行。
-cp <目录和 zip/jar 文件的类搜索路径>
-classpath <目录和 zip/jar 文件的类搜索路径>
用 : 分隔的目录, JAR 档案
和 ZIP 档案列表, 用于搜索类文件。
-D<名称>=<值>
设置系统属性
-verbose:[class|gc|jni]
启用详细输出
-version 输出产品版本并退出
-version:<值>
警告: 此功能已过时, 将在
未来发行版中删除。
需要指定的版本才能运行
-showversion 输出产品版本并继续
-jre-restrict-search | -no-jre-restrict-search
警告: 此功能已过时, 将在
未来发行版中删除。
在版本搜索中包括/排除用户专用 JRE
-? -help 输出此帮助消息
-X 输出非标准选项的帮助
-ea[:<packagename>...|:<classname>]
-enableassertions[:<packagename>...|:<classname>]
按指定的粒度启用断言
-da[:<packagename>...|:<classname>]
-disableassertions[:<packagename>...|:<classname>]
禁用具有指定粒度的断言
-esa | -enablesystemassertions
启用系统断言
-dsa | -disablesystemassertions
禁用系统断言
-agentlib:<libname>[=<选项>]
加载本机代理库 <libname>, 例如 -agentlib:hprof
另请参阅 -agentlib:jdwp=help 和 -agentlib:hprof=help
-agentpath:<pathname>[=<选项>]
按完整路径名加载本机代理库
-javaagent:<jarpath>[=<选项>]
加载 Java 编程语言代理, 请参阅 java.lang.instrument
-splash:<imagepath>
使用指定的图像显示启动屏幕
首先,我们从公共系统属性开始。这可以在 JVM 创建时传入,如下:
-D标志 表示后面的键值对将会作为JVM的系统属性,我们可以通过以下参数获取:
System.getProperty("blog"); //RebelLabs
相同的系统属性,也可以在系统启动的时候通过程序创建,就像下面这样:
System.setProperty("blog", "RL");
在 ZeroTurnaround,java agent 无非是我们的最爱!事实上,我们已经把它添加到了我们所有的产品中,从 JRebel 到 XRebel, 从 JRebel for Android 到 XRebel Hub!
java agent 非常像一个 JVM 插件,它使用了 Instrumentation API。通过它可以进行有趣的字节码操作,从而实现很多神奇的工具。要添加一个 java agent,只需指向一个包含 agent 代码和manifest 的jar包路径即可,如下:
-javaagent:/path/to/agent.jar
如果想要的 JVM运行时获得更多其内部运行的信息,可以使用-verbose 选项。你可以使用多种风味来收集不同的信息。这些信息包括 加载类(class)、垃圾回收(gc)、JNI(jni)的活动信息。下面的例子中我们将获得 垃圾回收的详细信息。所有信息都将已日志的形式打印到标准输出中。
非标准选项
像标准选项那样,你可以在命令行执行 java -X 召唤出完整的 非标准选项列表。下面附出我在本机执行的结果:
-Xmixed 混合模式执行 (默认)
-Xint 仅解释模式执行
-Xbootclasspath:<用 : 分隔的目录和 zip/jar 文件>
设置搜索路径以引导类和资源
-Xbootclasspath/a:<用 : 分隔的目录和 zip/jar 文件>
附加在引导类路径末尾
-Xbootclasspath/p:<用 : 分隔的目录和 zip/jar 文件>
置于引导类路径之前
-Xdiag 显示附加诊断消息
-Xnoclassgc 禁用类垃圾收集
-Xincgc 启用增量垃圾收集
-Xloggc:<file> 将 GC 状态记录在文件中 (带时间戳)
-Xbatch 禁用后台编译
-Xms<size> 设置初始 Java 堆大小
-Xmx<size> 设置最大 Java 堆大小
-Xss<size> 设置 Java 线程堆栈大小
-Xprof 输出 cpu 配置文件数据
-Xfuture 启用最严格的检查, 预期将来的默认值
-Xrs 减少 Java/VM 对操作系统信号的使用 (请参阅文档)
-Xcheck:jni 对 JNI 函数执行其他检查
-Xshare:off 不尝试使用共享类数据
-Xshare:auto 在可能的情况下使用共享类数据 (默认)
-Xshare:on 要求使用共享类数据, 否则将失败。
-XshowSettings 显示所有设置并继续
-XshowSettings:all
显示所有设置并继续
-XshowSettings:vm 显示所有与 vm 相关的设置并继续
-XshowSettings:properties
显示所有属性设置并继续
-XshowSettings:locale
显示所有与区域设置相关的设置并继续
-X 选项是非标准选项, 如有更改, 恕不另行通知。
以下选项为 Mac OS X 特定的选项:
-XstartOnFirstThread
在第一个 (AppKit) 线程上运行 main() 方法
-Xdock:name=<应用程序名称>"
覆盖停靠栏中显示的默认应用程序名称
-Xdock:icon=<图标文件的路径>
覆盖停靠栏中显示的默认图标
当 JVM 启动的时候,它使用默认的 bootstrap 类路径来加载引导类和资源。要覆盖默认的启动类路径,可以通过以下选项把 路径 和/或 归档列表 提供给 JVM。
你可以通过 -Xbootclasspath/a:path 和 -Xbootclasspath/p:path 分别追加或预加默认引导路径。
你是否厌烦了把 GC 事件作为日志输出到标准输出流?如果是,那么下面这个选项就是为你所准备!设置-Xloggc这个选项,并且提供一个你打算输出的目标文件路径!这个选项将会覆盖上节说到的-verbose:gc选项。
避免 JVM 在堆中崩溃的最好做法 就是一开始就设置堆的大小。但问题是 堆应该设置为多大?这取决于你的应用程序和打算用JVM来做什么。在确定最终应该设置多大之前,你应该不断的改变你的堆大小然后进行测量评估。你可以设置堆的初始字节和最大字节数,单位可以使用常用的 k、m、g。下面的示例设置JVM的初始堆大小是 1GB,如果不够,最大能增长到 8GB。
要禁用类的垃圾回收,可以用下面的选项。这样可以节省垃圾回收的时间,这时候只有对象才有资格被垃圾回收。当然,这样也增加了内存不足的风险,特别是在 使用了永久代空间的 Java 版本里。
我们讨论的最后一个非标准选项,将允许你 profile 运行中的 JVM。当然,它没有那些具有 漂亮UI和丰富功能 的工具易于理解和使用,例如 XRebel (而且很便宜)。但是下面这个参数很容易启用。所有的信息都会在标准输出显示。
这个备忘单由 XRebel 提供,它是一个在你工作中 提醒你的应用性能问题的工具,而不是让你的用户来发现这些问题。如果你正在开发 Java Web 程序,就应该尝试使用它。这个将会改变你对你程序表现的态度。
高级选项
行为(Behavior)
我们将围绕着垃圾回收这个主题开始。在 Java9 中,标准的垃圾回收器是 Garbage First Garbage Collector (G1GC),你也可以选择其它的垃圾回收器来执行垃圾回收策略。这些垃圾收集器包括 并发标记清除(Concurrent Mark Sweep (CMS))、并行扫描、串行 垃圾回收器,当然还包括G1GC。你可以通过下选项来启动它们。无需多说,请不要尝试同时使用多个选项来运行。
-XX:+UseConcMarkSweepGC
-XX:+UseParallelGC
-XX:+UseSerialGC
-XX:+UseG1GC
飞行记录器这(Flight Recorder)个功能是 JDK 内置的。它允许你获得有关应用和JVM的详细信息。和你期望的分析器功能类似,它将收集事件信息供你检查。为了使用这个功能,你需要使用单独的选项来解锁JVM的这个商业功能。这两个选项如下所示:
-XX:+FlightRecorder -XX:+UnlockCommercialFeatures
调试(Debugging)
如果你希望用一个专门的文件来查看错误数据,可以使用下面的选项 外加一个日志文件名。现在你就可以看到一个漂亮干净的日志文件,里面只有那些令人惊讶的错误!
想调试一个错误,但是却没有错误信息,没有什么比这个更令人沮丧了。最好的例子例子就是 常见的OutOfMemory错误。这个事件会让你的JVM瘫痪却不告诉你原因。使用下面这个选项可以帮到你。HeapDumpOnOutOfMemory 会为你提供一个包含大量调试信息的 .hprof 文件。你可以使用 Eclipse MAT 或者其他你喜欢的工具打开,它可以找出是什么囤积在堆里面。里面内容非常详细,你可以拿到最原始的对象,诊断出可能的内存泄露问题。
-XX:+HeapDumpOnOutOfMemory
如果你很想了解垃圾回收器如何工作,但是又不想使用-verbose:gc 打印沉长的完整详细信息,可以尝试 PrintGC 选项。每次执行垃圾回收时,它只简单的打印一条消息。
你对 什么时候 或 在什么条件下 你的类会被加载充满好奇吗?如果是,你可能需要看一下下面这个选项。这个选项可以追踪JVM加载的每个类。如果这种事情对你是有帮助的。
性能(Performance)
在你打算发牢骚之前声明一下,是的,我知道 永久代已经从 Java8 中移除了!但是,如果没有酷到使用最新版的版本,你会发现下面的这个参数很有用。如果你存在 PermGen 不够的问题,那么你会发现它很有用。你可以改变 PermGen 的最大大小,就像改变老年代堆大小一样。只需要提供你想要的最大字节数,如下:
你应该知道线程的栈内存空间并没有从堆中分配,因此当你使用 -Xms 和 -Xmx 选项的时候并不会对此产生影响。如果你想增加 甚至是减少线程栈空间大小,你可以像下面这样指定一定的字节数。
在 Java8 之前提供了一个有趣的UseStringCache 选项。这允许JVM缓存字符串。然而不幸的是它从 Java8 中移除了,而且没有可替换的选项。所以如果你想用到这个选项必须使用较早的版本。
如果你正在使用 G1GC,你应该非常熟悉这个区域的大小,并且了解什么是对你的应用有益。与所有的选项一样,你应该不断的尝试不同的值,然后进行评估。将来,G1GC 将成为 Java9 的标配,你需要和它成为最好的朋友。
我们之前提到的-Xms 和 -Xmx选项只适用于老年代堆。在大多数JVM中,Java 的堆空间还包含一个 年轻代 或者 托儿所(nursery) 堆。要设置年轻代的最大大小,可以使用一下选项。
如果你想让你的 JVM 性能很激进(angry and thirsty)的战斗,你可以使用下面这个 积极的性能优化功能。
总结
这篇文章文章中,我们涵盖了一些流行并且有趣的 Java 命令行选项。对于完整的 Java8选项列表,请查看 Oracle 官方文档。当你修改你的参数的时候,请务必记住,一定要不断的 测试、评估、迭代,以便正确的调优 JVM,尤其是在堆大小方面。
困惑
-Xms 和 -Xmx
原文在讲到 -XX:MaxNewSize=256m 这个参数的时候,说 -Xms 和 -Xmx 修改的是老年代的堆空间大小,感觉不是太对,因为印象中,这两个参数设置的是整个堆空间的大小,包含 新生代(年轻代)和旧生代(老年代)。
后续查了一下Oracle Garbage Collection Tuning Guide 官方文档中Total Heap这一节,
文中提到
the total size is bounded below by -Xms<min> and above by -Xmx<max>.
所以-Xms 和 -Xmx修改的是整个堆的大小,而不仅仅是老年代。
欢迎来到 第十个 RebelLabs 备忘单!这次我们将专注于那些你想用但是忽略掉的 JVM 选项。在这篇文章中,我们将介绍每个重要选项的功能。但是首先,让我们回顾一下下面10份备忘录,就要追溯到2015年12月份了!
我艹,太吊了(Wow, what a colorful journey! Here’s an amazing fact for you)。如果打印出上面所有的备忘录放在手边,那么你将腾出很多时间去做你喜欢的事。废话少说,点击下面的图片,打印出来吧,这样你就不用把那些该死的选项记在脑子里了。
让我们从上往下看。有三种类型的选项可以传递给 JVM:标准、非标准和高级选项。
-XX:开头;-X;我这样来告诉你,是不是发现好记了很多呢!下面,我们就从标准选项开始吧。
标准选项
如果你想获得所有的标准选项列表,只要在命令行输入
java即可,不需要携带任何参数,你想看到大量的标准选型并且带有使用说明。在这份备忘单中,我们选了一些最有趣的选项。这里附上我在执行
java时的输出:$ java 用法: java [-options] class [args...] (执行类) 或 java [-options] -jar jarfile [args...] (执行 jar 文件) 其中选项包括: -d32 使用 32 位数据模型 (如果可用) -d64 使用 64 位数据模型 (如果可用) -server 选择 "server" VM 默认 VM 是 server, 因为您是在服务器类计算机上运行。 -cp <目录和 zip/jar 文件的类搜索路径> -classpath <目录和 zip/jar 文件的类搜索路径> 用 : 分隔的目录, JAR 档案 和 ZIP 档案列表, 用于搜索类文件。 -D<名称>=<值> 设置系统属性 -verbose:[class|gc|jni] 启用详细输出 -version 输出产品版本并退出 -version:<值> 警告: 此功能已过时, 将在 未来发行版中删除。 需要指定的版本才能运行 -showversion 输出产品版本并继续 -jre-restrict-search | -no-jre-restrict-search 警告: 此功能已过时, 将在 未来发行版中删除。 在版本搜索中包括/排除用户专用 JRE -? -help 输出此帮助消息 -X 输出非标准选项的帮助 -ea[:<packagename>...|:<classname>] -enableassertions[:<packagename>...|:<classname>] 按指定的粒度启用断言 -da[:<packagename>...|:<classname>] -disableassertions[:<packagename>...|:<classname>] 禁用具有指定粒度的断言 -esa | -enablesystemassertions 启用系统断言 -dsa | -disablesystemassertions 禁用系统断言 -agentlib:<libname>[=<选项>] 加载本机代理库 <libname>, 例如 -agentlib:hprof 另请参阅 -agentlib:jdwp=help 和 -agentlib:hprof=help -agentpath:<pathname>[=<选项>] 按完整路径名加载本机代理库 -javaagent:<jarpath>[=<选项>] 加载 Java 编程语言代理, 请参阅 java.lang.instrument -splash:<imagepath> 使用指定的图像显示启动屏幕首先,我们从公共系统属性开始。这可以在 JVM 创建时传入,如下:
-D标志 表示后面的键值对将会作为JVM的系统属性,我们可以通过以下参数获取:相同的系统属性,也可以在系统启动的时候通过程序创建,就像下面这样:
在 ZeroTurnaround,java agent 无非是我们的最爱!事实上,我们已经把它添加到了我们所有的产品中,从 JRebel 到 XRebel, 从 JRebel for Android 到 XRebel Hub!
java agent 非常像一个 JVM 插件,它使用了 Instrumentation API。通过它可以进行有趣的字节码操作,从而实现很多神奇的工具。要添加一个 java agent,只需指向一个包含 agent 代码和manifest 的jar包路径即可,如下:
如果想要的 JVM运行时获得更多其内部运行的信息,可以使用
-verbose选项。你可以使用多种风味来收集不同的信息。这些信息包括 加载类(class)、垃圾回收(gc)、JNI(jni)的活动信息。下面的例子中我们将获得 垃圾回收的详细信息。所有信息都将已日志的形式打印到标准输出中。非标准选项
像标准选项那样,你可以在命令行执行
java -X召唤出完整的 非标准选项列表。下面附出我在本机执行的结果:-Xmixed 混合模式执行 (默认) -Xint 仅解释模式执行 -Xbootclasspath:<用 : 分隔的目录和 zip/jar 文件> 设置搜索路径以引导类和资源 -Xbootclasspath/a:<用 : 分隔的目录和 zip/jar 文件> 附加在引导类路径末尾 -Xbootclasspath/p:<用 : 分隔的目录和 zip/jar 文件> 置于引导类路径之前 -Xdiag 显示附加诊断消息 -Xnoclassgc 禁用类垃圾收集 -Xincgc 启用增量垃圾收集 -Xloggc:<file> 将 GC 状态记录在文件中 (带时间戳) -Xbatch 禁用后台编译 -Xms<size> 设置初始 Java 堆大小 -Xmx<size> 设置最大 Java 堆大小 -Xss<size> 设置 Java 线程堆栈大小 -Xprof 输出 cpu 配置文件数据 -Xfuture 启用最严格的检查, 预期将来的默认值 -Xrs 减少 Java/VM 对操作系统信号的使用 (请参阅文档) -Xcheck:jni 对 JNI 函数执行其他检查 -Xshare:off 不尝试使用共享类数据 -Xshare:auto 在可能的情况下使用共享类数据 (默认) -Xshare:on 要求使用共享类数据, 否则将失败。 -XshowSettings 显示所有设置并继续 -XshowSettings:all 显示所有设置并继续 -XshowSettings:vm 显示所有与 vm 相关的设置并继续 -XshowSettings:properties 显示所有属性设置并继续 -XshowSettings:locale 显示所有与区域设置相关的设置并继续 -X 选项是非标准选项, 如有更改, 恕不另行通知。 以下选项为 Mac OS X 特定的选项: -XstartOnFirstThread 在第一个 (AppKit) 线程上运行 main() 方法 -Xdock:name=<应用程序名称>" 覆盖停靠栏中显示的默认应用程序名称 -Xdock:icon=<图标文件的路径> 覆盖停靠栏中显示的默认图标当 JVM 启动的时候,它使用默认的 bootstrap 类路径来加载引导类和资源。要覆盖默认的启动类路径,可以通过以下选项把 路径 和/或 归档列表 提供给 JVM。
你可以通过
-Xbootclasspath/a:path和-Xbootclasspath/p:path分别追加或预加默认引导路径。你是否厌烦了把 GC 事件作为日志输出到标准输出流?如果是,那么下面这个选项就是为你所准备!设置
-Xloggc这个选项,并且提供一个你打算输出的目标文件路径!这个选项将会覆盖上节说到的-verbose:gc选项。避免 JVM 在堆中崩溃的最好做法 就是一开始就设置堆的大小。但问题是 堆应该设置为多大?这取决于你的应用程序和打算用JVM来做什么。在确定最终应该设置多大之前,你应该不断的改变你的堆大小然后进行测量评估。你可以设置堆的初始字节和最大字节数,单位可以使用常用的
k、m、g。下面的示例设置JVM的初始堆大小是 1GB,如果不够,最大能增长到 8GB。要禁用类的垃圾回收,可以用下面的选项。这样可以节省垃圾回收的时间,这时候只有对象才有资格被垃圾回收。当然,这样也增加了内存不足的风险,特别是在 使用了永久代空间的 Java 版本里。
我们讨论的最后一个非标准选项,将允许你 profile 运行中的 JVM。当然,它没有那些具有 漂亮UI和丰富功能 的工具易于理解和使用,例如 XRebel (而且很便宜)。但是下面这个参数很容易启用。所有的信息都会在标准输出显示。
这个备忘单由 XRebel 提供,它是一个在你工作中 提醒你的应用性能问题的工具,而不是让你的用户来发现这些问题。如果你正在开发 Java Web 程序,就应该尝试使用它。这个将会改变你对你程序表现的态度。
高级选项
行为(Behavior)
我们将围绕着垃圾回收这个主题开始。在 Java9 中,标准的垃圾回收器是
Garbage First Garbage Collector(G1GC),你也可以选择其它的垃圾回收器来执行垃圾回收策略。这些垃圾收集器包括 并发标记清除(Concurrent Mark Sweep(CMS))、并行扫描、串行 垃圾回收器,当然还包括G1GC。你可以通过下选项来启动它们。无需多说,请不要尝试同时使用多个选项来运行。飞行记录器这(
Flight Recorder)个功能是 JDK 内置的。它允许你获得有关应用和JVM的详细信息。和你期望的分析器功能类似,它将收集事件信息供你检查。为了使用这个功能,你需要使用单独的选项来解锁JVM的这个商业功能。这两个选项如下所示:调试(Debugging)
如果你希望用一个专门的文件来查看错误数据,可以使用下面的选项 外加一个日志文件名。现在你就可以看到一个漂亮干净的日志文件,里面只有那些令人惊讶的错误!
想调试一个错误,但是却没有错误信息,没有什么比这个更令人沮丧了。最好的例子例子就是 常见的
OutOfMemory错误。这个事件会让你的JVM瘫痪却不告诉你原因。使用下面这个选项可以帮到你。HeapDumpOnOutOfMemory会为你提供一个包含大量调试信息的.hprof文件。你可以使用Eclipse MAT或者其他你喜欢的工具打开,它可以找出是什么囤积在堆里面。里面内容非常详细,你可以拿到最原始的对象,诊断出可能的内存泄露问题。如果你很想了解垃圾回收器如何工作,但是又不想使用
-verbose:gc打印沉长的完整详细信息,可以尝试PrintGC选项。每次执行垃圾回收时,它只简单的打印一条消息。你对 什么时候 或 在什么条件下 你的类会被加载充满好奇吗?如果是,你可能需要看一下下面这个选项。这个选项可以追踪JVM加载的每个类。如果这种事情对你是有帮助的。
性能(Performance)
在你打算发牢骚之前声明一下,是的,我知道 永久代已经从 Java8 中移除了!但是,如果没有酷到使用最新版的版本,你会发现下面的这个参数很有用。如果你存在 PermGen 不够的问题,那么你会发现它很有用。你可以改变 PermGen 的最大大小,就像改变
老年代堆大小一样。只需要提供你想要的最大字节数,如下:你应该知道线程的栈内存空间并没有从堆中分配,因此当你使用
-Xms和-Xmx选项的时候并不会对此产生影响。如果你想增加 甚至是减少线程栈空间大小,你可以像下面这样指定一定的字节数。在 Java8 之前提供了一个有趣的
UseStringCache选项。这允许JVM缓存字符串。然而不幸的是它从 Java8 中移除了,而且没有可替换的选项。所以如果你想用到这个选项必须使用较早的版本。如果你正在使用 G1GC,你应该非常熟悉这个区域的大小,并且了解什么是对你的应用有益。与所有的选项一样,你应该不断的尝试不同的值,然后进行评估。将来,G1GC 将成为 Java9 的标配,你需要和它成为最好的朋友。
我们之前提到的
-Xms和-Xmx选项只适用于老年代堆。在大多数JVM中,Java 的堆空间还包含一个 年轻代 或者 托儿所(nursery) 堆。要设置年轻代的最大大小,可以使用一下选项。如果你想让你的 JVM 性能很激进(angry and thirsty)的战斗,你可以使用下面这个 积极的性能优化功能。
总结
这篇文章文章中,我们涵盖了一些流行并且有趣的 Java 命令行选项。对于完整的 Java8选项列表,请查看 Oracle 官方文档。当你修改你的参数的时候,请务必记住,一定要不断的 测试、评估、迭代,以便正确的调优 JVM,尤其是在堆大小方面。
困惑
-Xms 和 -Xmx
原文在讲到
-XX:MaxNewSize=256m这个参数的时候,说-Xms和-Xmx修改的是老年代的堆空间大小,感觉不是太对,因为印象中,这两个参数设置的是整个堆空间的大小,包含 新生代(年轻代)和旧生代(老年代)。后续查了一下Oracle Garbage Collection Tuning Guide 官方文档中Total Heap这一节,
文中提到
所以
-Xms和-Xmx修改的是整个堆的大小,而不仅仅是老年代。