JVM基础系列:JVM参数之堆栈空间配置
JVM中最重要的一部分就是堆空间,基本上大多数的线上JVM问题都是因为堆空间造成的OutOfMemoryError(OOM)。因此掌握JVM关于堆空间的参数配置对于排查线上问题非常重要。
PS: 本文所有配置,如果没有特殊说明,均是基于JDK1.8。
堆配置
我们使用-Xms设置推的初始空间大小,使用-Xms设置堆的最大空间大小。
java -Xms20m -Xmx30m GCDemo
上面的命令中,设置JVM堆的初始大小为20M,最大堆空间30M。
年轻代
在JDK1.8中,堆分为年轻代和老年代。JVM提供了参数-Xmn来设置年轻代内存的大小,但是没有提供设置老年代大小。但其实老年代大小就等于堆大小减去年轻代大小。
java -Xms20m -Xmn10m GCDemo
上面的命令中,我们设置JVM堆初始大小为20M。其中年轻代的大小为10M,那么老年代的大小就是10M了,可以加上XX:+PrintGCDetails 参数来查看内存区域的分配信息,如图所示,老年代大小为10M。
Eden区
在年轻代中,分为三个区域:eden、from、to空间。如果要设置这部分的大小,那么需要使用-XX:SurvivorRatio这个参数,该参数设置了eden与from区之间的比例关系。参数设置结果 : -XX:SurvivorRatio = eden/from = eden/to,比如年轻代有10M,而设置-XX:SurvivorRatio参数为2。也就是eden/from = 2,那么可以得出,在新生代为10M的时候,eden区为5M,from、to区各占2.5M。可以运行以下命令验证:
java -Xms20m -Xmn10m -XX:SurvivorRatio:2 -XX:+PrintGCDetails JVMDemo
从上图可以看到,eden占5120k,from和to占2560k。还有一个细节,可以看到PSYoungGen total只有7680k,为什么不是设置的10M?其实是因为total表示的是可用内存,from 区 和 to 区,在同一时间只有一个区域可以使用,另外一个区域使用来minor gc 使复制存活对象的。
永久代(JDK1.7)
在JDK1.8之前,所加载的类信息都放在永久代中,可以用+XX:PermSize设置永久代初始大小,用-XX:MaxPermSize设置永久代最大值。
java -XX:PermSize10m -XX:MaxPermSize50m -XX:+PrintGCDetails GCDemo
元空间(JDK1.8)
在1.8之前,所有加载的类信息都存放在永久代中,但1.8之后,永久代被移除,取而代之的是元空间(Metaspace)。在元空间这块内存中,有两个参数可以设置:-XX:MetaspaceSize和-XX:MaxMetaspaceSize。
java -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=50m -XX:+PrintGCDetails GCDemo
从执行结果可以看到,Metaspace空间大小大概为26M,并不是设置的10M,那是MetaspaceSize 表示的并非是元空间的大小,它的含义是:主要控制matespaceGC发生的初始阈值,也就是最小阈值。也就是说当使用的matespace空间到达了MetaspaceSize的时候,就会触发Metaspace的GC。MaxMetaspaceSize表示的是保证committed的内存不会超过这个值,一旦超过这个值就会触发GC。MetaspaceSize默认值是20.8M,而MaxMetaspaceSize默认基本是机器的物理内存大小,建议设置一下,如果一直不断膨胀,那么JVM进程可能会被OS kill 掉。
PS:在jvm启动的时候,并不会分配MaxMetaspaceSize这么大的一块内存出来,metaspace是可以一直扩容的,直到到达MaxMetaspaceSize。
栈空间
栈空间是每个线程各自占用的一块区域,如果栈空间太小,也会导致StackOverFlow异常,设置栈空间大小,可以使用-Xss参数,设置最大栈空间为2M。
java -Xss2m GCDemo
直接内存
在JVM中还有一块内存,它独立于JVM的堆内存,他就是:直接内存。可以使用-XX:MaxDirectMemorySize设置最大内存。如果不设置,默认为醉倒堆空间大小。即-Xmx。
java -XX:MaxDirectMemorySize=50m GCDemo
当直接内存使用达到设置值时,就会触发垃圾回收,如果不能有效释放足够空间,就会引发直接内存泄漏导致系统的OOM。
总结
参数 | 含义 |
---|---|
-Xms | 初始堆大小 |
-Xmx | 最大堆空间 |
-Xmn | 设置新生代大小 |
-XX:SurvivorRatio | 设置新生代eden空间和from/to空间的比例关系 |
-XX:PermSize | 方法区初始大小 |
-XX:MaxPermSize | 方法区最大大小 |
-XX:MetaspaceSize | 元空间GC阈值(JDK1.8) |
-XX:MaxMetaspaceSize | 最大元空间大小(JDK1.8) |
-Xss | 栈大小 |
-XX:MaxDirectMemorySize | 直接内存大小,默认为最大堆空间 |