性能测试中常见问题的排查方法

内存溢出和内存泄露

内存溢出 out of memory

是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory

内存泄露 memory leak

是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。memory leak会最终会导致out of memory!较为常见的有java.lang.OutOfMemoryError: Java heap space

样例测试代码

public class TestHeapOOM {

    static class Key {

        Integer id;

        Key(Integer id) {

            this.id = id;

        }

        @Override

        public int hashCode() {

            return id.hashCode();

        }

    }

    public static void main(String[] args) {

        Map<Key, String> m = new HashMap<>();

        while (true) {

            for (int i = 0; i < 10000; i++) {

                Key key = new Key(i);

                if (!m.containsKey(key)) {

                    m.put(key, "Number:" + i);

                }

            }

        }

    }

}

打成jar包后,运行

java -Xms512m -Xmx512m -XX:+UseG1GC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:./gc.log -jar TestHeapOOM-1.0-SNAPSHOT.jar &

运行一段时间后抛出:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

        at java.lang.Integer.valueOf(Integer.java:832)

        at com.wosai.qa.test_heap_oom.main(test_heap_oom.java:27)

堆内存一直增加,没有下降趋势(回收速度赶不上增长速度), 最后不断触发FullGC, 甚至crash

通过visualgc可以看到老生代持续增加

通过jstat可以看到老生代持续增加

分析gc日志可以看到多从老生代gc无法回收内存后,触发Full GC,之后多次Full GC后进程crash

问题的排查

jmap -histo:live pid查看jvm堆中具体情况

注意:jmap -histo:live 会触发Full gc,请谨慎使用

导出整个JVM 中内存信息,通过其他工具导入文件再分析,比如jvisualvm jmap -dump:format=b,file=文件名 [pid]

CPU使用率过高

样例测试代码

public class TestCpuHighUsage {

    public static void main(String[] args) {

        int num = args[0].toString() == null ? 1 : Integer.parseInt(args[0].toString());

        System.out.println("args[0] is " + num);

        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(num);

        final AtomicLong atomic = new AtomicLong(0);

        for (int i = 0; i < num; i++) {

            fixedThreadPool.execute(() -> {

                while (true) {

                    String str = Thread.currentThread().getName();

                    atomic.incrementAndGet();

                    if (atomic.get() > 999999) {

                        System.out.println("============>" + str);

                        atomic.set(0);

                    }

                }

            });

        }

    }

}

htop 或者top -Hp pid查看哪些线程cpu使用率较高

找到cpu使用率较高的线程id后,转成16进制

superuser@t1-test-004:/app/data/jvmtest$ jstack 5149获取进程中线程调用栈信息,并根据上一步的16进制找到对应的线程调用栈信息

————————————————

版权声明:本文为CSDN博主「WillFX」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/xffxnn/article/details/86107171

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容