JVM调优由浅到深(四)——JVM内存分配参数详解
- 常用参数设置
- 设置最大堆内存
- 设置最小堆内存
- 设置新生代
- 设置持久代
- 设置线程栈
- 堆的内存分配
- 堆分配参数总结
我们在这一篇文章中已经大概了解到了jvm的参数有哪些,大概怎么设置。
JVM调优由浅到深(一)——jvm参数配置
现在我们再来详细得再更加详细分析一次;
常用参数设置
设置最大堆内存
参数说明 | 例子 |
最大堆内存 | -Xmx10m |
在运行时,可以使用 Runtime.getRuntime().maxMemory() 取得系统可用的最大堆内存。
public void test5(){
System.out.println(Runtime.getRuntime().maxMemory()/1024/1024);
}
运行结果:
设置最小堆内存
参数说明 | 例子 |
最小堆内存 | -Xms10m |
Java应用程序在运行时,首先被分配-Xms指定的内存大小,并尽可能尝试在这个空间段内运行程序。
当-Xms指定的内存大小确实无法满足应用程序时,JVM 才会向操作系统申请更多的内存,直到内存大小达到-Xmx指定的最大内存为止。
若超过-Xmx的值,则抛出 OutOfMemoryError 异常。
如果 -Xms 的数值较小,那么JVM为了保证系统尽可能地在指定内存范围内运行,就会更加频繁地进行GC操作,以释放失效的内存空间。
从而,会增加 Minor GC 和 Full GC的次数,对系统性能产生一定的影响
因此把 -Xms 值设置为 -Xmx 时,可以在系统运行初期减少 GC 的次数和耗时。
设置新生代
参数说明 | 例子 |
新生代 | -Xmn2m |
设置一个较大的新生代会减少老年代的大小,这个参数对系统性能以及 GC 行为有很大的影响。
新生代的大小一般设置为整个堆空间的1/4到1/3左右。
在 Hot Spot 虚拟机中,-XX:NewSize 用于设置新生代的初始大小,
-XX:MaxNewSize用于设置新生代的最大值。
但通常情况下,只设置 -Xmn 以及可以满足绝大部分应用的需要。
设置 -Xmn 的效果等同于设置了相同的-XX:NewSize 和 -XX:MaxNewSize。
若设置不同的-XX:NewSize 和 -XX:MaxNewSize可能会导致内存震荡,从而产生不必要的系统开销。
设置持久代
持久代(方法区)不属于Java堆的一部分。在Hot Spot虚拟机中,使用-XX:MaxPermSize可以设置持久代的最大值,使用-XX:PermSize可以设置持久代的初始大小。
JDK1.8取消了PermGen,取而代之的是Metaspace(元空间),
所以PermSize和MaxPermSize参数失效,取而代之的是 -XX:MetaspaceSize
和 -XX:MaxMetaspaceSize。
参数说明 | 例子 |
持久代的初始大小 | -XX:MetaspaceSize=64M |
持久代的最大值 | -XX:MaxMetaspaceSize=128M |
持久代的大小直接决定了系统可以支持多少个类定义和多少常量。
对于使用 CGLIB 或者 Javassist 等动态字节码生成工具的应用程序而言,
设置合理的持久代大小有助于维持系统稳定。
一般来说,设置MaxMetaspaceSize为64MB已经可以满足绝大部分应用程序正常工作。
如果依然出现永久区溢出,可以将MaxMetaspaceSize设置为128MB。
这是两个很常用的永久区取值。
设置线程栈
线程栈是线程的一块私有空间。有关描述可以参考前文的“Java虚拟机栈”。
参数说明 | 例子 |
线程栈大小 | -Xss1M |
在线程中进行局部变量分配,函数调用时,都需要在栈中开辟空间。
如果栈的空间分配太小,那么线程在运行时,可能没有足够的空间分配局部变量或者达不到足够的函数调用深度,导致程序异常退出;
如果栈空间过大,那么开设线程所需的内存成本就会上升,系统所能支持的线程总数就会下降。
由于Java堆也是向操作系统申请内存空间的,
因此,如果堆空间过大,就会导致操作系统可用于线程栈的内存减少,
从而间接减少程序所能支持的线程数量。
当系统由于内存不够无法创建新的线程时,会抛出 OOM 异常如下:
java.lang.OutOfMemoryError: unable to create new native thread
根据以上内容可知,这并不是由于堆内存不够而导致的 OOM,而是因为操作系统内存减去堆内存后,剩余的系统内存不足而无法创建新的线程。
在这种情况下,可以尝试减少堆内存,以换取更多的系统空间,来解决这个问题。
如果系统确实需要大量的线程并发执行,那么设置一个较小的堆和较小的栈,
有助于提供系统所能承受的最大线程数。
堆的内存分配
参数说明 | 例子 |
eden区/survivor区 | -XX:SurvivorRatio=8 |
老年代/新生代 | -XX:NewRatio=2 |
参数 -XX:SurvivorRatio 是用来设置新生代中,eden空间和s0空间的比例关系。
s0 和 s1 空间又被称为 from 空间和 to 空间。
它们的大小是相同的,职能也是一样的,并在 Minor GC后,会互换角色。
公式:-XX:SurvivorRatio = eden/s0 = eden/s1
举例:当设置JVM参数 -Xmn10M -XX:SurvivorRatio=8 就等于设置 eden=8M,s0=1M,s1=1M。
参数 -XX:NewRatio 是用来设置新生代与老年代的比例:
公式:-XX:NewRatio = 老年代 / 新生代
举例:当设置JVM参数 -Xms18M -Xmx18M -XX:NewRatio=2运行程序时,新生代约占6MB,老年代约占12MB。
堆分配参数总结
参数说明 | 例子 |
-Xmx | 设置Java应用程序能获得的最大堆 |
-Xms | 设置Java应用程序启动时的初始堆 |
-Xss | 设置新生代的初始大小与最大值 |
-Xmn | 设置新生代的初始大小与最大值 |
-XX:NewSize | 设置新生代的大小。 |
-XX:NewRatio | 设置老年代与新生代的比例,它等于老年代大小除以新生代大小。 |
-XX:SurvivorRatio | 设置新生代中eden区和survivor区的比例 |
-XX:MetaspaceSize | XX |
-XX:MetaspaceSize | (Java8)设置永久区的初始值。。 |
-XX:MaxMetaspaceSize | (Java8)最大的持久区大小。 |
-XX:MinHeapFreeRatio | 设置堆空间的最大空闲比例,当堆空间的空闲内存小于这个数值时,JVM便会扩展堆空间 |
-XX:MaxHeapFreeRatio | 设置堆空间的最大空闲比例。当堆空间的空闲内存大于这个数值时,便会压缩堆空间,得到一个较小的堆。 |
-XX:TargetSurvivorRatio | 设置survivor区的可使用率。当survivor区的空间使用率达到这个值时,会将对象送入老年代。 |