常用的java虚拟机参数有哪些

发布时间:2021-11-18 10:00:55 作者:iii
来源:亿速云 阅读:126

这篇文章主要介绍“常用的java虚拟机参数有哪些”,在日常操作中,相信很多人在常用的java虚拟机参数有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”常用的java虚拟机参数有哪些”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

1. 掌握跟踪调试参数

1.1 跟踪垃圾回收
1 打印垃圾回收日志:-XX:+PrintGC(在jdk9、jdk10中建议使用-Xlog:gc)

最简单的一个GC参数是-XX:+PrintGC(在jdk9、jdk10中建议使用-Xlog:gc),使用这个参数启动jvm后,只要遇到GC,就会打印日志。

[GC 4893K->377K(15872K), 0.0006926 secs]

一行记录表示进行了一次GC,该GC记录显示,在GC前,堆空间使用量约为4MB,在GC后,堆空间使用量为377KB,当前堆空间的总和约为16MB(15872K)。最后显示的是本次GC所花的时间。

jdk9、jdk10默认使用G1作为垃圾回收器,使用参数-Xlog:gc来打印GC日志,如下图所示:

[0.012s][info][gc] Using G1
[0.107s][info][gc] GC(0) Pause Full (System.gc()) 16M->7M(34M) 23.511ms

该日志显示,一共进行了一次GC,在GC前,堆空间使用量为16MB,在GC后,堆空间使用量为7MB,当前堆空间总和为34MB。最后,显示的是本次GC所花的时间,为23.511ms。

2. 打印垃圾回收日志详情:-XX+PrintGCDetails(在jdk9、jdk10中建议使用-Xlog:gc*)

如果需要更加详细的信息,可以使用-XX:+PrintGCDetails(在jdk9、jdk10中建议使用-Xlog:gc*)参数。该参数会使虚拟机在退出前打印堆的详细信息,详细信息描述了当前堆的各个区间的使用情况。

3. 输出GC前后堆的信息:-XX:+PrintHeapAtGc(从jdk9起,已删除该参数)

如果需要更全面的堆信息,还可以使用-XX:+PrintHeapAtGc(考虑到兼容性,从jdk9起,已删除该参数,查看堆信息可以使用Visual VM)。它会在每次GC前、后分别打印堆的信息,就如同-XX+PrintGCDetails的最后输出一样。

4. 关注GC引起的应用程序停顿

由于GC会引起应用程序停顿,因此还需要特别关注应用程序的执行时间和停顿时间。使用参数-XX:+PrintGCApplicationConcurrentTime可以打印应用程序的执行时间,使用参数-XX:+PrintGCApplicationStoppedTime可以打印应用程序由于GC而产生的停顿时间。

5. 跟踪系统内的软引用、弱引用、虚引用和Finallize队列

如果想跟踪系统内的软引用、弱引用、虚引用和Finallize队列,可以打开-XX:+PrintReferenceGC(考虑到兼容性,从jdk9开始已经删除此参数,查看堆信息可以使用Visual VM)开关。

6. 指定gc日志位置

默认情况下,GC的日志会在控制台中输出,这不便后续分析和定位问题。所以虚拟机允许将GC日志以文件的形式输出,可以使用参数-Xloggc指定。

比如,使用参数-Xloggc:log/gc.log(在jdk9、jdk10中建议使用-Xlog:gc:/log/gc.log)启动虚拟机,可以在当前目录的log文件夹下的gc.log文件中记录所有的GC日志。

1.2 类加载/卸载的跟踪

java程序的运行离不开类的加载,为了更好地理解程序如何执行,有时候需要知道系统加载了哪些类。

1.3 查看系统参数

由于目前的java虚拟机支持众多的可配参数,不同的参数可能对系统的执行效果有较大的影响,因此有必要明确当前系统的实际运行参数。虚拟机提供了一些手段来帮助研发人员获得这些参数。

2. 堆的配置参数

2.1 初始堆与最大堆

初始堆与最大堆分别使用-Xms-Xmx来指定,如指定初始堆大小为5MB、最大堆大小为20MB:-Xms5m-Xmx20m。在实际生产中,为了减少程序运行时垃圾回收的次数,一般直接将初始堆-Xms与最大堆-Xmx设置为相等。

2.2 新生代配置

参数-Xmn可以用于设置新生代的大小,设置一个较大的新生代减少老年代的大小,这个参数对系统性能及GC行为有很大的影响。** 新生代的大小一般设置为整个堆空间的 1/31/4 **.

参数-XX:SurvivorRatio 用来设置新生代中eden区和from/to区的比例,它的含义如下:

-XX:SurvivorRatio = eden/form = eden/to

示例:

public class Demo02 {
    public static void main(String[] args) {
        byte[] b = null;
        for(int i = 0; i < 10; i++) {
            b = new byte[2 * 1024 * 1024];
        }
    }
}
(1) 使用参数 -Xmx40m -Xms40m -Xmn2m -XX:SurvivorRatio=2 -XX:+PrintGCDetails 运行
[GC (Allocation Failure) [PSYoungGen: 1024K->432K(1536K)] 1024K->432K(40448K), 0.0015289 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 PSYoungGen      total 1536K, used 885K [0x00000007bfe00000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 1024K, 44% used [0x00000007bfe00000,0x00000007bfe716b0,0x00000007bff00000)
  from space 512K, 84% used [0x00000007bff00000,0x00000007bff6c010,0x00000007bff80000)
  to   space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
 ParOldGen       total 38912K, used 20480K [0x00000007bd800000, 0x00000007bfe00000, 0x00000007bfe00000)
  object space 38912K, 52% used [0x00000007bd800000,0x00000007bec000a0,0x00000007bfe00000)
 Metaspace       used 3066K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 337K, capacity 388K, committed 512K, reserved 1048576K

这里的 eden区from区 的比值为2:1,故 eden区 为1024kb,总可用新生代大小为1024kb + 512kb = 1536kb,新生代总大为1024kb+512kb+512kb=2048kb=2mb.

由于eden区无法容纳任何程序中分配的2MB的数组,故触发了一次新生代gc,对eden区进行了部分回收。同时,这个偏小的新生代无法为2MB数组预留空间,故所有的数组都分配在老年代,老年代最终占用20480K空间。

(2) 使用参数 -Xmx40m -Xms40m -Xmn14m -XX:SurvivorRatio=2 -XX:+PrintGCDetails 运行
[GC (Allocation Failure) [PSYoungGen: 5477K->2560K(10752K)] 5477K->2568K(37376K), 0.0016892 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 8915K->2592K(10752K)] 8923K->2600K(37376K), 0.0015561 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 9050K->2544K(10752K)] 9058K->2552K(37376K), 0.0009707 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
Heap
 PSYoungGen      total 10752K, used 6871K [0x00000007bf200000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 7168K, 60% used [0x00000007bf200000,0x00000007bf639d28,0x00000007bf900000)
  from space 3584K, 70% used [0x00000007bf900000,0x00000007bfb7c020,0x00000007bfc80000)
  to   space 3584K, 0% used [0x00000007bfc80000,0x00000007bfc80000,0x00000007c0000000)
 ParOldGen       total 26624K, used 8K [0x00000007bd800000, 0x00000007bf200000, 0x00000007bf200000)
  object space 26624K, 0% used [0x00000007bd800000,0x00000007bd802000,0x00000007bf200000)
 Metaspace       used 2970K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 328K, capacity 388K, committed 512K, reserved 1048576K

本次将新生代扩大为14MB(7168k+3584K+3584k=14336K),在这个参数下,由于eden区有足够的空间,因此所有的数组都分配在eden区。但eden区并不足以预留10MB的空间,故在程序运行期间出现了3次新生代gc.由于每申请一次空间,同时也废弃了上一次申请的空间(上一次申请的内存失去了引进),故在新生代gc中,有效回收了这些失效的内存。最终结果是:所有的内存分配都在新生代进行,通过gc保证了新生代有足够的空间,而老年代没有为这些数组预留任何空间,只是在gc过程中,部分新生代对象晋升到老年代。

(3) 使用参数 -Xmx40m -Xms40m -Xmn30m -XX:SurvivorRatio=8 -XX:+PrintGCDetails 运行
Heap
 PSYoungGen      total 27648K, used 23437K [0x00000007be200000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 24576K, 95% used [0x00000007be200000,0x00000007bf8e3510,0x00000007bfa00000)
  from space 3072K, 0% used [0x00000007bfd00000,0x00000007bfd00000,0x00000007c0000000)
  to   space 3072K, 0% used [0x00000007bfa00000,0x00000007bfa00000,0x00000007bfd00000)
 ParOldGen       total 10240K, used 0K [0x00000007bd800000, 0x00000007be200000, 0x00000007be200000)
  object space 10240K, 0% used [0x00000007bd800000,0x00000007bd800000,0x00000007be200000)
 Metaspace       used 3064K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 336K, capacity 388K, committed 512K, reserved 1048576K

在这次执行中,由于新生代使用30MB空间,其中eden占24MB(30MB / 10 * 8 ),完全满足10MB数组的分配,因此所有的分配行为都在eden区直接进行,且没有触发任何GC行为。因此,from/to和老年代的使用率都为0

由此可见,不同的堆分布情况对系统会产生一定的影响。在实际工作中,应该根据系统的特点做合理的设置,基本策略是:尽可能将对象预留在新生代,减少老年代gc的次数

(4) 使用参数 -Xmx40m -Xms40m -XX:NewRatio=2 -XX:+PrintGCDetails

除了可以使用参数 -Xmn 指定新生代的绝对大小,还可以使用参数 -XX:NewRatio 来设置新生代和老年代的比例,如下所示:

-XX:NewRatio=老年代/新生代

本例中,设置的老年代与新生代的比例为2:1.运行结果如下:

[GC (Allocation Failure) [PSYoungGen: 10075K->496K(11776K)] 10075K->2552K(39424K), 0.0019760 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 8989K->560K(11776K)] 11045K->4672K(39424K), 0.0015192 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
Heap
 PSYoungGen      total 11776K, used 5144K [0x00000007bf300000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 10240K, 44% used [0x00000007bf300000,0x00000007bf77a088,0x00000007bfd00000)
  from space 1536K, 36% used [0x00000007bfe80000,0x00000007bff0c010,0x00000007c0000000)
  to   space 1536K, 0% used [0x00000007bfd00000,0x00000007bfd00000,0x00000007bfe80000)
 ParOldGen       total 27648K, used 4112K [0x00000007bd800000, 0x00000007bf300000, 0x00000007bf300000)
  object space 27648K, 14% used [0x00000007bd800000,0x00000007bdc04020,0x00000007bf300000)
 Metaspace       used 3044K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 333K, capacity 388K, committed 512K, reserved 1048576K

此时,堆的大小为40MB,新生代和老年代的比为1:2,故新生代大小为40*(1/3)=14MB(其中,eden约为14MB*(8/10)=11.2MB,from/to大小为14*(1/10)=1.4MB),老年代约为26MB。由于在新生代GC时,from/to空间不足以容纳任何一个2MB数组,影响了新生代的正常回收,故在新生代回收时需要老年代进行空间担保。这导致两个2MB数组进入老年代(在新生代gc时,尚有1MB数组幸存,理应进入from/to区,而from/to区只有1.4MB,不足以容纳)。

2.3 堆内存溢出

在java程序的运行过程中,如果堆空间不足,则有可能会抛出内存溢出,简称OOM:

public class Demo03 {
    public static void main(String[] args) {
        Vector vector = new Vector();
        for(int i = 0; i < 25; i++) {
            vector.add(new byte[1*1024*1024]);
        }
    }
}

使用参数 -Xmx20m -Xms20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./dump.log 启动,结果如下:

java.lang.OutOfMemoryError: Java heap space
Dumping heap to ./dump.log ...
Heap dump file created [19887142 bytes in 0.015 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at jvm.chapter03.Demo03.main(Demo03.java:16)

可以看到,虚拟机将当前的堆栈信息导出,并保存到dump.out文件中。

除了在发生OOM时可以导出堆信息,虚拟机还允许在发生错误时执行一个脚本文件。该文件可以用于崩溃程序的自救、报警或通知,也可以帮助开发人员获得更多的系统信息,如完整的线程保存。

3. 非堆内存的参数配置

3.1 方法区配置

jdk 1.6jdk 1.7 等版本中,可以使用 -XX:PermSize-XX:MaxPermSize 配置永久区大小 。其中,-XX:PermSize 表示初始的永久区大小,-XX:MaxPermSize 表示最大永久区大小。

jdk1.8 开始,永久区被彻底移除,使用了新的元数据区存放类的元数据。在默认情况下,元数据区只受系统可用内存的限制,但依然可以使用参数 -MaxMetaspaceSize 指定永久区的最大可用值。

3.2 直接内存配置

在NIO被广泛使用后,直接内存的使用变得非常普遍,直接内存跳过了Java堆,使用Java程序可以直接访问原生堆空间。因此,从一定程度上加快了内存空间的访问速度。

最大可以直接内存可以使用参数 -XX:MaxDirectMemorySize 设置。如果不设置,默认值为最大堆空间,即-Xmx 的值。当直接内存使用量达到 -XX:MaxDirectMemorySize 时,就会触发垃圾回收,如果垃圾回收不能有效释放足够的空间,直接内存溢出依然会引起系统的OOM.

直接内存的访问速度比堆内存快;在申请空间时,堆内存的速度远远快于直接内存。因此,直接内存适合申请次数较少、访问频繁的场合。如果需要频繁申请内存空间,则并不适合使用直接内存

3. Client与Server:虚拟机的工作模式

目前,java虚拟机支持 ClientServer 两种运行模式,使用参数 -client 可以指定使用 Client模式,使用参数 -server 可以指定使用 Server模式 。在默认情况下,虚拟机会根据当前计算机系统环境自动选择运行模式。使用-version参数可以查看当前模式:

java version "1.8.0_201"
Java(TM) SE Runtime Environment (build 1.8.0_201-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.201-b09, mixed mode)

server模式启动较client模式慢,因为server模式会尝试收集更多的系统性能信息,使用更复杂的算法对程序进行优化。因此,当系统完全启动并进入运行稳定期后,server模式的执行速度会远远快于client模式``。对于长期运行的系统更适合server模式,但对于用户界面程序而言,运行时间不长,又追求启动速度,更适合client模式

虚拟机在server模式client模式下的各种参数可能会有很大不同,可以使用-XX:+PrintFlagsFinal查看参数的默认值,这里以查看 CompileThresholdMaxHeapSize 为例,示例如下:

对于 client模式

 $ java -XX:+PrintFlagsFinal -client -version | grep -E 'CompileThreshold | MaxHeapSize'
     intx CompileThreshold                          = 10000                               {pd product}
    uintx MaxHeapSize                              := 4294967296                          {product}
     intx Tier2CompileThreshold                     = 0                                   {product}
     intx Tier3CompileThreshold                     = 2000                                {product}
     intx Tier4CompileThreshold                     = 15000                               {product}
java version "1.8.0_201"
Java(TM) SE Runtime Environment (build 1.8.0_201-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.201-b09, mixed mode)

对于 server模式

$ java -XX:+PrintFlagsFinal -server -version | grep -E 'CompileThreshold | MaxHeapSize'
     intx CompileThreshold                          = 10000                               {pd product}
    uintx MaxHeapSize                              := 4294967296                          {product}
     intx Tier2CompileThreshold                     = 0                                   {product}
     intx Tier3CompileThreshold                     = 2000                                {product}
     intx Tier4CompileThreshold                     = 15000                               {product}
java version "1.8.0_201"
Java(TM) SE Runtime Environment (build 1.8.0_201-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.201-b09, mixed mode)

到此,关于“常用的java虚拟机参数有哪些”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

推荐阅读:
  1. Oracle中RMAN的BACKUP常用参数有哪些
  2. 使用mysqldump有哪些常用参数

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:如何探究IE和Firefox下的2款HTTP调试工具用法

下一篇:JDK如何安装

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》