1、内存分配相关调优
1.1、最大与最小堆内存设置
Java 应用程序在运行时,首先会被分配 -Xms 指定的内存大小,并尽可能尝试在这个空间段内运行程序。当 -Xms 指定的内存大小确实无法满足应用程序时, JVM 才会向操作系统中请更多的内存,直到内存大小达到 -Xmx 指定的最大内存为止。若超过 -Xmx 的值,则抛出 OutOfMemoryError 异常。如果 -Xms 的数值较小,那么 JVM 为了保证系统尽可能地在指定内存范围内运行,就会更加频繁地进行 GC 操作,以释放失效的内存空间,从而,会增加 Minor GC 和 Full GC 的次数,对系统性能产生一定的影响。
JVM会试图将系统内存尽可能限制在-Xms中,故当内存时间使用量触及-Xms指定的大小时,会被触发Full GC。因此把-Xms值设置为-Xms时,可以在系统运行初期减少GC的次数和耗时。
1.2、设置新时代
参数 -Xmn 用于设置新生代的大小。设置一个较大的新生代会减小老年代的大小,这个参数对系统性能以及 GC 行为有很大的影响。新生代的大小一般设置为整个堆空间的 1/4 到1/3左右。
在 Hot spot 虚拟机中,-XX : NewSize 用于设置新生代初始大小, -XX : MaxNewSize用于设置新生代的最大值。但通常情况下,只设置 -Xmn 已经可以满足绝大部分应用的需要。设置 -Xmn 的效果等同于设置了相同的 -XX : NewSize 和 -XX : MaxNewSize 。
若设置不同的-XX:NewSize和-XX:MaxNewSize可能导致内存震荡,从而产生不必要的系统开销。
1.3、设置持久代
持久代(方法区)不属于堆的一部分。在 Hot Spot 虚拟机中,使用 -XX : MaxPermSize 可以设义持久代的最大值,使用 -XX : PermSize 可以设置持久代的初始大小。
持久代的大小直接决定了系统可以支持多少个类定义和多少常量。对于使用 CGLIB 或者 Javassist 等动态字节码生成工具的应用程序而言,设置合理的持久代大小有助于维持系统稳定。
一般来说, MaxPermSize 设置为 64MB 已经可以满足绝大部分应用程序正常工作。如果依然出现永久区溢出,可以将 MaxPermSize设置为 128MB 。这是两个很常用的永久区取值。如果 128MB 依然不能满足应用程的需求,那么对于大部分应用程序来说,则应该考虑优化系统的设计,减少动态类的产生。
1.4、设置线程栈
在 JVM 中,可以使用 -Xss 参数设置线程栈的大小。
在线程中,进行局部变从分配,函数调用时,都需要在栈中开辟空间。如果栈的空间分配太小,那么线程在运行时,可能没有足够的空间分配局部变量或者达不到足够的函数调用深度,导致程序异常退出:如果栈空间过大,那么开设线程所需的内存成本就会上升,系统所能支持的线程总数就会下降。由于 Java 堆也是向操作系统申请内存空间的,因此,如果堆空间过大,就会导致操作系统可用于线程栈的内存减少,从而间接减少程序所能支持的线程数数量。
故如果系统确实需要大量线程并发执行,那么设置一个较小的堆和较小的栈,有助于提高系统所能承受的最大线程数。