JVM常用参数的介绍

x33g5p2x  于2021-10-09 转载在 Java  
字(3.1k)|赞(0)|评价(0)|浏览(537)

本文将分门别类地介绍一些常用的JVM的参数,包括:

  • 内存相关参数
  • 显示GC日志的参数
  • 类加载的相关参数
  • 显示启动参数的参数
  • 如何查看所有参数的默认值

内存相关参数

堆空间的配置

  • -Xmx 指定堆内存的最大空间,设置方式:-Xmx<value>
  • -Xms 指定堆内存的初始空间,设置方式:-Xms<value>

oracle官方推荐将初始堆Xms与最大堆Xmx设置为相等。这样的好处是,可以减少程序运行时进行垃圾回收的次数,同时也减少了虚拟机需要做出决策的数量,这些可以提高程序的性能。

我的经验是,如果java进程的可用内存在4G以内(含),我会配置堆空间占50%的内存。如果java进程的可用内存大于4G,那么我会配置堆空间60%的内存。举例:如果一个docker容器的内存limit是4G,那么我会配置 -Xmx2048m -Xms2048m

新生代的配置

堆的大小设置完了以后,来分配堆里面的新生代内存。

  • -XX:NewRatio 指定老年代与新生代的比例。
  • -XX:MaxNewSize=size 指定新生代的最大空间。
  • -XX:NewSize=size 指定新生代的初始空间。

堆空间由新生代和老年代组成,老年代是兜底的区域,如果空间太小的话,要么频繁Full GC,要么进程OOM。-XX:NewRatio的默认值是2,意味着老年代是新生代的两倍,新生代为堆空间的1/3。如果你想更保守的话,可以设置为3,意味着新生代只占堆空间的1/4,老年代更大,缺点是可能会带来更频繁的新生代GC。

  • -XX:SurvivorRatio 指定新生代中的eden区与s0和s1的比例。默认值是8,意味着eden区默认是s0和s1的8倍。

non-heap 配置

在JDK1.6和JDK1.7等版本中,可以使用-XX:PermSize和XX:MaxPermSize配置永久区大小。其中,-XX:PermSize表示初始的永久区大小,-XX:MaxPermSize表示最大永久区大小。

从JDK1.8开始,永久区被彻底移除,使用了新的元数据区存放类的元数据。在默认情况下,元数据区只受系统可用内存的限制,但依然可以使用参数-XX:MetaspaceSize-XX:MaxMetaspaceSize指定永久区的初始值和最大值。-XX:MetaspaceSize的默认值是20M,而-XX:MaxMetaspaceSize没有最大值。推荐的配置为:

-XX:MetaspaceSize=96m -XX:MaxMetaspaceSize=256m。

使用-Xss指定线程栈的大小,默认是1M。可以通过Xss256k来指定每个线程栈的大小为256k。

直接内存也是Java程序中非常重要的组成部分,特别是在NIO被广泛使用后,直接内存的使用也变得非常普遍。直接内存跳过了Java堆,使Java程序可以直接访问原生堆空间。因此,从一定程度上加快了内存空间的访问速度。但是,武断地认为使用直接内存一定可以提高内存访问速度也是不正确的。最大可用直接内存可以使用参数-XX:MaxDirectMemorySize设置,如果不设置,默认值为最大堆空间,即-Xmx的值。当直接内存使用量达到-XX:MaxDirectMemorySize时,就会触发垃圾回收,如果垃圾回收不能有效释放足够的空间,直接内存溢出依然会引起系统的OOM。

OOM处理

可以通过配置参数-XX:+HeapDumpOnOutOfMemoryError,当java堆出现内存溢出时会导出整个堆的信息。配合-XX:HeapDumpPath=<path>,可以指定导出堆的存放路径。

除此以外,在OOM发生时还可以通过-XX:OnOutOfMemoryError=<my-script>来执行一个脚本。其中,<my-script>可以是一个脚本文件,也可以是多条命令,其中的%p将会被替换为pid。例如:

-XX:OnOutOfMemoryError="jstack -F %p > jstack.txt "

显示GC日志的参数

输出GC日志

-XX:+PrintGC(在JDK9、JDK10中建议使用`-Xlog:gc`)

输出GC的时间

-XX:+PrintGCDateStamps

如果同时配置以上的两个参数,则会产生类似的GC日志

2021-10-07T15:27:57.471+0800: [GC pause (G1 Evacuation Pause) (young) 657M->74M(2048M), 0.0229247 secs] 
2021-10-07T23:49:54.850+0800: [GC pause (G1 Evacuation Pause) (young) 657M->72M(2048M), 0.0279736 secs] 
2021-10-08T08:11:09.035+0800: [GC pause (G1 Evacuation Pause) (young) 657M->72M(2048M), 0.0278149 secs]

我们可以看出GC发生的时间,GC的类型(young GC),堆的占用空间从657M降到了70多M,堆的空间上限为2048M,GC的过程用时0.02秒等信息。

输出更加详细的GC日志

如果需要更加详细的信息,可以使用-XX:+PrintGCDetails参数。(JDK9、JDK10建议使用-Xlog:gc/*)。

它会在日志中分别输出堆的各区域的内存回收情况。

将GC日志输出到文件

默认情况下,GC的日志会在控制台中输出,这不便于后续分析和定位问题。所以,虚拟机允许将GC日志以文件的形式输出,可以使用参数-Xloggc:<logfile>指定。(在JDK9、JDK10中建议使用-Xlog:gc:<logfile>

垃圾回收器参数

从JDK9开始,G1收集器被设为了默认的垃圾收集器,所以我在这里只列跟G1相关的参数

-XX:+UseG1GC:使用G1回收器;
-XX:MaxGCPauseMillis=xxx:设置最大垃圾回收停顿时间,默认值是200。

类加载的相关参数

可以使用参数-verbose:class跟踪类的加载/卸载。

也可以单独使用参数-XX:+TraceClassLoading跟踪类的加载,使用参数-XX:+TraceClassUnloading跟踪类的卸载。这两类参数是等价的。

显示启动参数的参数

查看实际应用的所有参数

通过-XX:+PrintCommandLineFlags参数,可以在java进程启动时打印当前进程实际应用的所有参数。

查看显式设定的参数

通过-XX:+PrintVMOptions参数,可以在java进程启动时打印我们显式地为当前java进程设置了哪些参数。

当然,也可以直接运行jps -v命令来查看java进程显式设置的参数。

如何查看所有参数的默认值

以下命令可以显示当前机器上的jdk版本的所有参数的默认值

java -XX:+PrintFlagsFinal -version

配合grep就可以查看你想查看的参数的默认值了。比如查看NewRatio的默认值到底是几比几:

$ java -XX:+PrintFlagsFinal -version |grep NewRatio
    uintx NewRatio                                  = 2                                   {product}
java version "1.8.0_291"
Java(TM) SE Runtime Environment (build 1.8.0_291-b10)
Java HotSpot(TM) 64-Bit Server VM (build 25.291-b10, mixed mode)

相关文章