浅谈JVM调优

JVM调优小白,理论知识走一波

首先如果条件允许(内存在8G以上)选择G1,领先PN+CMS和PS+PO不只是一两个数量级。但是我们更期待ZGC的到来,在ZGC成为stable之前还是得有一点点了解。
在这里插入图片描述

吞吐量优先,选择PS+PO
低延迟选择PN+CMS

几个重要的参数

  1. -XX:MaxTenuringThreshold=2 表示该对象经过多少次GC后晋升到老年代,但是JVM在进行GC时也会判断年轻代一半以上的对象的最小年龄,把大于该年龄的晋升到老年代。
  2. -XX:ParallelGCThreads=4 & -XX:ConGCThreads=3 并发收集线程数。得看具体应用的CPU逻辑核心数,需要多次迭代。
  3. -XX:UseBiasedLocking 偏向锁,会尝试把锁赋值给第一个访问它的线程,渠道同步块上的synchronized原语。在安全点日志里,可以看到很多RevokeBiased的记录,高并发环境下建议取消,因为所撤销也需要耗时。
  4. -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

是不是很神奇~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值