JVM 调优有许多参数优化,下面整理了一些我自己能够理解的参数,后面慢慢补充
-XX:AutoBoxCacheMax
-XX:+AlwaysPreTouch
CMSInitiatingOccupancyFraction
MaxTenuringThreshold
ExplicitGCInvokesConcurrent
-Xmx, -Xms
NewRatio
-XX:AutoBoxCacheMax
JAVA 进程启动的时候,会加载 rt.jar 这个核心包的,rt.jar 包里的 Integer 自然也是被加载到 JVM 中,Integer 里面有一个 IntegerCache 缓存,如下:
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
}
private IntegerCache() {}
}
IntegerCache 有一个静态代码块,JVM 在加载 Integer 这个类时,会优先加载静态的代码。当 JVM 进程启动完毕后, -128 ~ +127 范围的数字会被缓存起来,调用 valueOf 方法的时候,如果是这个范围内的数字,则直接从缓存取出。
超过这个范围的,就只能构造新的 Integer 对象了。
public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
因此可以根据实际情况把 AutoBoxCacheMax 的值设置的大写,比如江南白衣推荐的
-XX:AutoBoxCacheMax=20000
-XX:+AlwaysPreTouch
JAVA 进程启动的时候,虽然我们可以为 JVM 指定合适的内存大小,但是这些内存操作系统并没有真正的分配给 JVM,而是等 JVM 访问这些内存的时候,才真正分配,这样会造成以下问题。
1、GC 的时候,新生代的对象要晋升到老年代的时候,需要内存,这个时候操作系统才真正分配内存,这样就会加大 young gc 的停顿时间;
2、可能存在内存碎片的问题。
可以在 JVM 启动的时候,配置
-XX:+AlwaysPreTouch
参数,这样 JVM 就会先访问所有分配给它的内存,让操作系统把内存真正的分配给 JVM.后续 JVM 就可以顺畅的访问内存了。
JAVA 1.7 用的垃圾收集算法还是 CMS,下文提到的参数都是针对 CMS 的。
CMSInitiatingOccupancyFraction
java 垃圾回收算法之-CMS(并发标记清除),垃圾收集线程会跟应用的线程一起并行的工作,万一垃圾收集线程在工作的时候,老年代内存不足怎么办?因此最好还是提前启动 CMS 来收集垃圾(CMS GC)。
可以通过设置
CMSInitiatingOccupancyFraction=75
那么当老年代堆空间的使用率达到 75% 的时候就开始执行垃圾回收,CMSInitiatingOccupancyFraction 默认值是 92%,这个就太大了。
CMSInitiatingOccupancyFraction 参数必须跟下面两个参数一起使用才能生效的。
-XX:+UseConcMarkSweepGC
-XX:+UseCMSInitiatingOccupancyOnly
MaxTenuringThreshold
新生代是使用 copy 算法来进行垃圾回收的,可以参看
java 垃圾回收算法之-coping 复制
默认情况下,当新生代执行了 15 次 young gc 后,如果还有对象存活在 Survivor 区中,那么就可以直接将这些对象晋升到老年代,但是由于新生代使用 copy 算法,如果 Survivor 区存活的对象太久的话,Survivor 区存活的对象就越多,这个就会影响 copy 算法的性能,使得 young gc 停顿的时间加长,建议设置成 6。
-XX:MaxTenuringThreshold=6
ExplicitGCInvokesConcurrent
如果系统使用堆外内存,比如用到了 Netty 的 DirectByteBuffer 类,那么当想回收堆外内存的时候,需要调用
System.gc()
而这个方法将进行 full gc,整个应用将会停顿,如果是使用 CMS 垃圾收集器,那么可以设置
-XX:+ExplicitGCInvokesConcurrent
这个参数来改变 System.gc()
的行为,让其从 full gc --> CMS GC,CMS GC 是并发收集的,且中间执行的过程中,只有部分阶段需要 stop the world。
注意:设置了 ExplicitGCInvokesConcurrent,那就不要设置 DisableExplicitGC 参数来禁掉 System.gc()
。
-Xmx, -Xms
这两个一般都是设置 4 个 g
NewRatio
GC 最多的还是发生在新生代的 young gc,所以可以提高一下新生代在整个堆的占用比例,建议设置为对半分,尽量避免 young gc
-XX:NewRatio=1
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于