JVM常用配置参数及分析

JVM常用配置参数及分析

薛定谔的汪

最近学习了JVM的一些常用参数,今天正好是周末,就花些时间总结一下,加深印象。

JVM常用的配置参数

Trace跟踪参数

-XX:+PrintGCDetails打印GC详细信息:

1
2
3
4
5
6
7
8
9
10
11
Heap                                         //起始边界    当前边界    最大边界 
def new generation total 4928K, used 796K [0x25000000, 0x25550000, 0x2a550000)
eden space 4416K, 18% used [0x25000000, 0x250c7098, 0x25450000)
from space 512K, 0% used [0x25450000, 0x25450000, 0x254d0000)
to space 512K, 0% used [0x254d0000, 0x254d0000, 0x25550000)
tenured generation total 10944K, used 0K [0x2a550000, 0x2b000000, 0x35000000)
the space 10944K, 0% used [0x2a550000, 0x2a550000, 0x2a550200, 0x2b000000)
compacting perm gen total 12288K, used 193K [0x35000000, 0x35c00000, 0x39000000)
the space 12288K, 1% used [0x35000000, 0x35030730, 0x35030800, 0x35c00000)
ro space 10240K, 44% used [0x39000000, 0x3947b1c8, 0x3947b200, 0x39a00000)
rw space 12288K, 52% used [0x39a00000, 0x3a0431d0, 0x3a043200, 0x3a600000)

def new generation:新生代内存描述:总共4928K,已使用796K

eden space:eden区内存描述

from space::from survivor区内存描述

to space: to survivor区内存描述

tenured generation:老年代内存描述

compacting perm gen:永久代内存描述

-Xloggc:log/gc.log

指定GC log的文件位置,以文件输出

帮助开发人员分析问题

-XX:+PrintGCAtGC

每一次GC后打印堆得信息,这个打印的GC是很详尽的,可能帮助我们很方便地处理问题。

-XX:TraceClassLoading

监控类的加载:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[Loaded java.lang.Object from shared objects file] 
[Loaded java.io.Serializable from shared objects file]
[Loaded java.lang.Comparable from shared objects file]
[Loaded java.lang.CharSequence from shared objects file]
[Loaded java.lang.String from shared objects file]
[Loaded java.lang.reflect.GenericDeclaration from shared objects file]
[Loaded java.lang.reflect.Type from shared objects file]
[Loaded java.lang.reflect.AnnotatedElement from shared objects file]
[Loaded java.lang.Class from shared objects file]
[Loaded java.lang.Cloneable from shared objects file]
[Loaded java.lang.ClassLoader from shared objects file]
[Loaded java.lang.System from shared objects file]
[Loaded java.lang.Throwable from shared objects file]
[Loaded java.lang.Error from shared objects file]
[Loaded java.lang.ThreadDeath from shared objects file]
[Loaded java.lang.Exception from shared objects file]
[Loaded java.lang.RuntimeException from shared objects file]
......

堆的分配参数

-Xms -Xmx

堆得初始空间和最大空间(可以配置堆是否可扩展)

如-Xms5m -Xmx20m 配置堆初始化5m,最大20m。

-Xmn

设置新生代大小

-XX:NewRatio

新生代和老生代的比值,如果设置为5,表示新生代:老生代=1:5。

-XX:SurvivorRatio

新生代中Eden和两个Survivor的比值:默认是8 即:8:1:1

堆得分配参数实战

示例代码:

1
2
3
4
5
6
7
8
9
10
11
package test.demo;

public class TestJvmArgs {
public static void main(String[] args) {
//10次循环,每次new一个1m大小的byte数组
byte[] barr = null;
for (int i = 0; i < 10; i++) {
barr=new byte[1024*1024];
}
}
}

堆示例参数一:

咱们设置jvm启动参数 -Xms20m -Xmx20m -Xmn1m -XX:+PrintGCDetails 设置堆固定20m大小,新生代1m,并打印GC详情。

GC日志:

1
2
3
4
5
6
7
8
9
10
11
Heap
def new generation total 960K, used 640K [0x33c00000, 0x33d00000, 0x33d00000)
eden space 896K, 71% used [0x33c00000, 0x33ca0230, 0x33ce0000)
from space 64K, 0% used [0x33ce0000, 0x33ce0000, 0x33cf0000)
to space 64K, 0% used [0x33cf0000, 0x33cf0000, 0x33d00000)
tenured generation total 19456K, used 10240K [0x33d00000, 0x35000000, 0x35000000)
the space 19456K, 52% used [0x33d00000, 0x347000a0, 0x34700200, 0x35000000)
compacting perm gen total 12288K, used 193K [0x35000000, 0x35c00000, 0x39000000)
the space 12288K, 1% used [0x35000000, 0x35030760, 0x35030800, 0x35c00000)
ro space 10240K, 44% used [0x39000000, 0x3947b1c8, 0x3947b200, 0x39a00000)
rw space 12288K, 52% used [0x39a00000, 0x3a0431d0, 0x3a043200, 0x3a600000)

通过GC日志我们得出,没有出现GC。因为新生代比较小,eden区也就才896k,不够存放我们new出的1m大小的对象,所以对象直接被分配大了老年代。

住:我们给新生代分配的是1m,但是日志显示的是960k,这是因为新生代使用了GC的复刻算法(以后会有讲解),from和to 幸存区只能用一个,1024-64=960。

堆示例参数二:

-Xms20m -Xmx20m -Xmn15m -XX:+PrintGCDetails

这次分配新生代的大小为15m,运行后我们观察GC日志:

1
2
3
4
5
6
7
8
9
10
11
Heap
def new generation total 13824K, used 11469K [0x33c00000, 0x34b00000, 0x34b00000)
eden space 12288K, 93% used [0x33c00000, 0x34733640, 0x34800000)
from space 1536K, 0% used [0x34800000, 0x34800000, 0x34980000)
to space 1536K, 0% used [0x34980000, 0x34980000, 0x34b00000)
tenured generation total 5120K, used 0K [0x34b00000, 0x35000000, 0x35000000)
the space 5120K, 0% used [0x34b00000, 0x34b00000, 0x34b00200, 0x35000000)
compacting perm gen total 12288K, used 193K [0x35000000, 0x35c00000, 0x39000000)
the space 12288K, 1% used [0x35000000, 0x35030780, 0x35030800, 0x35c00000)
ro space 10240K, 44% used [0x39000000, 0x3947b1c8, 0x3947b200, 0x39a00000)
rw space 12288K, 52% used [0x39a00000, 0x3a0431d0, 0x3a043200, 0x3a600000)

发现这次也没有发生GC,本次eden区大小是12288k,足够存放10个1m的对象。

根据对象分配优先在eden区分配原则,本次所有对象都分配到了eden区,没有对象进入老年代。

堆示例参数三:

-Xms20m -Xmx20m -Xmn7m -XX:+PrintGCDetails

这次分配新生代的大小是7m,运行程序观察GC日志:

1
2
3
4
5
6
7
8
9
10
11
12
[GC[DefNew: 5075K->467K(6464K), 0.0019326 secs] 5075K->1491K(19776K), 0.0019733 secs][Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC[DefNew: 5827K->0K(6464K), 0.0014499 secs] 6851K->2515K(19776K), 0.0014736 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
def new generation total 6464K, used 1081K [0x04a00000, 0x05100000, 0x05100000)
eden space 5760K, 18% used [0x04a00000, 0x04b0e6e0, 0x04fa0000)
from space 704K, 0% used [0x04fa0000, 0x04fa00e0, 0x05050000)
to space 704K, 0% used [0x05050000, 0x05050000, 0x05100000)
tenured generation total 13312K, used 2514K [0x05100000, 0x05e00000, 0x05e00000)
the space 13312K, 18% used [0x05100000, 0x05374b78, 0x05374c00, 0x05e00000)
compacting perm gen total 12288K, used 1759K [0x05e00000, 0x06a00000, 0x09e00000)
the space 12288K, 14% used [0x05e00000, 0x05fb7e60, 0x05fb8000, 0x06a00000)
No shared spaces configured.

通过日志我们发现发生了两次新生代GC。分析如下:

新生代大小配置为7m,eden区5m多,前5次循环对象都进入了eden区,占用了5m,当循环第6次的时候eden区不够了,发生gc,由于from survivor区和to只有704k,不够放下任何一个对象。通过内存担保机制,有一部分对象晋升至老年代。第二次GC也是如此。

我们总共创建了10*1024=10240K大小的对象,第一次新生代GC回收了5075K-1491K=3584K,第二次新生代GC回收了4336K,一共回收了7920K,二者相减即GC后留在内存中的对象。

堆示例参数四:

-Xms20m -Xmx20m -Xmn7m -XX:SurvivorRatio=2 -XX:+PrintGCDetails

在参数三的基础上,修改eden:from:to=2:1:1

观察GC日志:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[GC[DefNew: 2710K->1419K(5376K), 0.0020251 secs] 2710K->1419K(18688K), 0.0020618 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC[DefNew: 4607K->1024K(5376K), 0.0015099 secs] 4607K->1418K(18688K), 0.0015494 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew: 4125K->1024K(5376K), 0.0003962 secs] 4519K->1418K(18688K), 0.0004140 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
def new generation total 5376K, used 3163K [0x33c00000, 0x34300000, 0x34300000)
eden space 3584K, 59% used [0x33c00000, 0x33e16c18, 0x33f80000)
from space 1792K, 57% used [0x34140000, 0x34240010, 0x34300000)
to space 1792K, 0% used [0x33f80000, 0x33f80000, 0x34140000)
tenured generation total 13312K, used 394K [0x34300000, 0x35000000, 0x35000000)
the space 13312K, 2% used [0x34300000, 0x34362a80, 0x34362c00, 0x35000000)
compacting perm gen total 12288K, used 193K [0x35000000, 0x35c00000, 0x39000000)
the space 12288K, 1% used [0x35000000, 0x35030780, 0x35030800, 0x35c00000)
ro space 10240K, 44% used [0x39000000, 0x3947b1c8, 0x3947b200, 0x39a00000)
rw space 12288K, 52% used [0x39a00000, 0x3a0431d0, 0x3a043200, 0x3a600000)

我们发现发生了3次新生代的gc,这样配置的话GC是有点多了。

堆示例参数五:

-Xms20m -Xmx20m -Xmn10m -XX:SurvivorRatio=2 -XX:+PrintGCDetails

观察GC日志:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[GC[DefNew: 4870K->1419K(7680K), 0.0014811 secs] 4870K->1419K(17920K), 0.0015174 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC[DefNew: 5625K->1024K(7680K), 0.0012109 secs] 5625K->1418K(17920K), 0.0012294 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
def new generation total 7680K, used 3161K [0x33c00000, 0x34600000, 0x34600000)
eden space 5120K, 41% used [0x33c00000, 0x33e16538, 0x34100000)
from space 2560K, 40% used [0x34100000, 0x34200098, 0x34380000)
to space 2560K, 0% used [0x34380000, 0x34380000, 0x34600000)
tenured generation total 10240K, used 394K [0x34600000, 0x35000000, 0x35000000)
the space 10240K, 3% used [0x34600000, 0x346629f8, 0x34662a00, 0x35000000)
compacting perm gen total 12288K, used 193K [0x35000000, 0x35c00000, 0x39000000)
the space 12288K, 1% used [0x35000000, 0x35030780, 0x35030800, 0x35c00000)
ro space 10240K, 44% used [0x39000000, 0x3947b1c8, 0x3947b200, 0x39a00000)
rw space 12288K, 52% used [0x39a00000, 0x3a0431d0, 0x3a043200, 0x3a600000)

这次发生了两次GC,因为新生代内存比之前大了,我们再修改下。

堆示例参数六:

-Xms20m -Xmx20m -Xmn10m -XX:SurvivorRatio=3 -XX:+PrintGCDetails

GC日志如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
[GC[DefNew: 5858K->1419K(8192K), 0.0016146 secs] 5858K->1419K(18432K), 0.0016648 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
def new generation total 8192K, used 6731K [0x33c00000, 0x34600000, 0x34600000)
eden space 6144K, 86% used [0x33c00000, 0x34130150, 0x34200000)
from space 2048K, 69% used [0x34400000, 0x34562cb8, 0x34600000)
to space 2048K, 0% used [0x34200000, 0x34200000, 0x34400000)
tenured generation total 10240K, used 0K [0x34600000, 0x35000000, 0x35000000)
the space 10240K, 0% used [0x34600000, 0x34600000, 0x34600200, 0x35000000)
compacting perm gen total 12288K, used 193K [0x35000000, 0x35c00000, 0x39000000)
the space 12288K, 1% used [0x35000000, 0x35030780, 0x35030800, 0x35c00000)
ro space 10240K, 44% used [0x39000000, 0x3947b1c8, 0x3947b200, 0x39a00000)
rw space 12288K, 52% used [0x39a00000, 0x3a0431d0, 0x3a043200, 0x3a600000)

这次只发生了一次GC,有兴趣的也可以自己尝试下哈。

-XX:+HeapDumpOnOutOfMemoryError

发生OOM时导出堆到文件

-XX:+heapDumpPath

导出OOM的路径 与上一个参数配合使用。

-XX:OnOutOfMemoryError

在OOM时执行一个脚本。

如:-XX:OnOutOfMemoryError=E:/JavaEE/Jdk/jdk1.7.0_72/bin/printStack.bat %p

当发生OOM时执行printStack.bat脚本,linux上是.sh文件,这个脚本可将对oom信息转存到文件。

如:E:/JavaEE/Jdk/jdk1.7.0_72/bin/jstack -F %1 > E:/a.txt

也可以执行发送邮件,甚至是重启服务器。

堆常用参数总结:

  1. 根据实际情况合理配置堆得内存,最大内存,新生代,老生代内存等。
  2. 合理调整新生代和老生代比例,官方推荐和默认比例是3:8
  3. eden:from:to的默认比例是8:1:1
  4. 在发生OOM时,一定要dump出堆信息,确保可以排查问题。

永久区常用分配参数:

-XX:PermSize -XX:MaxPermSize

配置永久区初始值和最大值,主要储存Class对象的相关信息。

栈的分配参数

-Xss

每个线程的栈帧大小,通常只有几百k到1m,决定了函数调用的深度,是线程独立的。

当我们想增大最大线程数时,也可以通过适当减少这个值,当我们想要函数调用的深一些,可以增大这个值。

  • Title: JVM常用配置参数及分析
  • Author: 薛定谔的汪
  • Created at : 2017-11-26 18:36:09
  • Updated at : 2023-11-17 19:37:37
  • Link: https://www.zhengyk.cn/2017/11/26/jvm/JVM-04/
  • License: This work is licensed under CC BY-NC-SA 4.0.