JVM调优小白,理论知识走一波
首先如果条件允许(内存在8G以上)选择G1,领先PN+CMS和PS+PO不只是一两个数量级。但是我们更期待ZGC的到来,在ZGC成为stable之前还是得有一点点了解。
吞吐量优先,选择PS+PO
低延迟选择PN+CMS
几个重要的参数
- -XX:MaxTenuringThreshold=2 表示该对象经过多少次GC后晋升到老年代,但是JVM在进行GC时也会判断年轻代一半以上的对象的最小年龄,把大于该年龄的晋升到老年代。
- -XX:ParallelGCThreads=4 & -XX:ConGCThreads=3 并发收集线程数。得看具体应用的CPU逻辑核心数,需要多次迭代。
- -XX:UseBiasedLocking 偏向锁,会尝试把锁赋值给第一个访问它的线程,渠道同步块上的synchronized原语。在安全点日志里,可以看到很多RevokeBiased的记录,高并发环境下建议取消,因为所撤销也需要耗时。
- -XX:UseCountedLoopSafepoints 在每一个循环下面都放置一个安全点,建议开启。
jvm默认会在可数的循环结束放置一个循环点,什么是可数呢?就是你平常写的for(int i = 0; i< 100; i ++) 但是会引发一个问题,如果这个循环耗时很长,那么其他线程到达了安全点,你这个循环没有结束,就会导致其他线程一直在等待你循环结束,所以建议开启,在每个循环后面都加上,这样ygc时间就很短了
不信? 做个实验:
package jvm;
import java.util.function.Consumer;
/**
* @author wenbaox
* @version 1.0
* @date 2021/7/27 下午4:59
* thread: Thread-0, costs 1002 ms
* thread: Thread-0, costs 6267 ms
* thread: Thread-0, costs 1004 ms
* thread: Thread-0, costs 1004 ms
* thread: Thread-0, costs 4671 ms
* 加入,让在
* -XX:+UseCountedLoopSafepoints
* 强制在每一个counted loop后面插入SafePoint代码
* 之后基本不会超过1010毫秒
*/
public class TestBlockingThread {
static Consumer<Long> sleep = millis -> {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
}
};
//t1总是发生尖刺,因为是无界循环,jvm会在循环结束放置一个停顿点,但是因为一直在循环就在里面进行了gc
static Thread t1 = new Thread(() -> {
while (true) {
long start = System.currentTimeMillis();
sleep.accept(1000L);
long cost = System.currentTimeMillis() - start;
(cost > 1010L ? System.err : System.out).printf("thread: %s, costs %d ms\n",
Thread.currentThread().getName(), cost);
}
}, "t1");
//t2是一个可数循环,jvm默认在循环结束才方式一个安全点
static Thread t2 = new Thread(() -> {
while (true) {
//改成long就没有问题了
for (int i = 1; i <= 1000000000; i++) {
boolean b = 1.0 / i == 0;
}
long start = System.currentTimeMillis();
sleep.accept(1000L);
long cost = System.currentTimeMillis() - start;
(cost > 1010L ? System.err : System.out).printf("thread: %s, costs %d ms\n",
Thread.currentThread().getName(), cost);
}
}, "t2");
public static final void main(String[] args) {
t1.start();
sleep.accept(1500L);
t2.start();
}
}
上面t1线程最长有等待8秒的
开启之后
-XX:+UseCountedLoopSafepoints
发现没有了,并且将循环改为long也可以(原理不懂的可以看看参数含义)
thread: t1, costs 1005 ms
thread: t1, costs 1007 ms
thread: t1, costs 1010 ms
thread: t1, costs 1013 ms
thread: t1, costs 1012 ms
thread: t1, costs 1010 ms
thread: t1, costs 1009 ms
thread: t1, costs 1010 ms
是不是很神奇~