您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > JAVA

从异常堆栈信息丢失,探究jvm的性能优化

时间:2020-04-18 09:31:47  来源:  作者:

从异常堆栈信息丢失,探究jvm的性能优化

异常堆栈丢失

今天登陆服务器进行例行的检查,发现异常日志文件里有很多nullPointException,只有简单的异常名称,却没有堆栈信息。没有异常堆栈,无法定位错误,也就不能修改了。到网上搜索信息,原来大家也遇到过这样的问题。

正确的解决方法是增加一个VM Options:-XX:-OmitStackTraceInFastThrow。这个参数的好处如下:

“JVM对一些特定的异常类型做了Fast Throw优化,如果检测到在代码里某个位置连续多次抛出同一类型异常的话,C2会决定用Fast Throw方式来抛出异常,而异常Trace即详细的异常栈信息会被清空。这种异常抛出速度非常快,因为不需要在堆里分配内存,也不需要构造完整的异常栈信息。”

这个参数,支持的异常类型如下:

  • NullPointerException
  • ArithmeticException
  • ArrayIndexOutOfBoundsException
  • ArrayStoreException
  • ClassCastException

翻阅了大量的关于此问题的文章,介绍信息大同小异。通过这个方案,开启输出空指针错误,很快就定位问题,并解决了。

解决问题后,进行了一番的测试和验证,如下:

问题验证

众多网络文章,都指出在异常出现5000次以上时,才会丢失堆栈信息。按照网络文章的测试代码,在6600多次的时候丢失堆栈信息,但是并不稳定。代码如下:

public class JAVANPE extends Thread {
    private static int count = 0;
    @Override
    public void run() {
        try {
            System.out.println("getSimpleName is:"+this.getClass().getSimpleName() + " execute count:" + (++count));
            String str = null;
            System.out.println(str.length());
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
}

public class TestFastThrow {
    public static void main(String[] args) throws InterruptedException {
        JavaNPE javaNPE = new JavaNPE();
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            executorService.execute(javaNPE);
            //防止打出的日志太快
            Thread.sleep(2);
        }
    }
}

这是一个多线程的程序,写单线程的测试程序,是否可行呢?于是就尝试了第一版,代码如下:

   public static void main(String args[]) {
        for (int i = 0; i < 10000; i++) {
            try {
                String value = null;
                value.substring(0, 100);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

但是,很遗憾,这个程序的异常堆栈信息并不会丢失。程序修改如下:

   public void method2() {
        String value = null;
        value.substring(0, 100);
    }

    public static void main(String args[]) {
        ExceptionTest exceptionTest = new ExceptionTest(1);
        for (int i = 0; i < 10000; i++) {
            try {
                exceptionTest.method2();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

这个程序在第5530~5550次的时候,会丢失异常堆栈信息,是不稳定的。分析上述两段单线程的测试代码,第一段因为异常信息没有到方法的外面,jvm不能追踪到异常堆栈信息,所以并不会起作用。

性能优化明显吗?

首先,在网络上的文章,都着重说C2编译器的优化,并没有说明C1编译器。通过我的实验,C1和C2编译器的默认行为是一样的,都是开启OmitStackTraceInFastThrow的。C1和C2编译器,是指Java及时编译技术(JIT),在启动应用程序是,java -client是启动C1编译器;java -server是启动C2编译器。

这个参数真的有性能优化吗?测试代码没有IO输出,纯测试代码的执行速度,测试代码如下:

    public void testPerformance() {
        long start = System.currentTimeMillis();
        System.out.println("start");
        for (int i = 0; i < 1000 * 1000; i++) {
            try {
                this.method();
            } catch (Exception ex) {

            }
        }
        System.out.println("used " + (System.currentTimeMillis() - start));
    }

    public void method() {
        String value = null;
        value.substring(0, 100);
    }

测试结果如下:

从异常堆栈信息丢失,探究jvm的性能优化

 

测试结果发现,关闭堆栈后性能确实有了很大的提升,在输出堆栈的情况下,性能随着调用次数的增多,呈线性增长。

测试代码中的堆栈信息,只有一层,把调用异常堆栈的深度增加到20,是不是创建的对象而更多,耗时时间更长呢?关闭参数的情况下,确实是,调用1M次,时间增加到由13秒增加到20秒;启用参数的情况下,耗时却从400毫秒减少到150毫秒!

经测试发现:同样都是在5500多次的时候,丢掉异常的堆栈信息。并且20层异常堆栈,执行这5500多次,耗时120毫秒;层数较少的只用了70毫秒。也就是说,堆栈层数越多,丢掉堆栈后的性能越好!具体是什么原因,就需要阅读源代码了!如果你知道,欢迎留言探讨。

 

 



Tags:jvm   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
大家好!我是老码农,一个喜欢技术、爱分享的同学,从今天开始和大家持续分享JVM调优方面的经验。JVM调优是个大话题,涉及的知识点很庞大 Java内存模型 垃圾回收机制 各种工具使用 ...【详细内容】
2021-12-23  Tags: jvm  点击:(11)  评论:(0)  加入收藏
亿级流量电商系统JVM模型参数预估方案,在原来的基础上采用ParNew+CMS垃圾收集器一、亿级流量分析及jvm参数设置1. 需求分析大促在即,拥有亿级流量的电商平台开发了一个订单系...【详细内容】
2021-10-25  Tags: jvm  点击:(41)  评论:(0)  加入收藏
为什么要有JVM? JVM就是Java运行虚拟机,那么虚拟机又分为系统虚拟机和程序虚拟机,而JVM是属于程序虚拟机,所以不要看到是虚拟机就误认为JVM是系统虚拟机。 JVM是帮助Java程序开...【详细内容】
2021-06-09  Tags: jvm  点击:(155)  评论:(0)  加入收藏
JVM架构 从上图可以很清晰的看出,jvm架构分成三大部分 类加载子系统 运行时数据区 执行引擎1,类加载子系统Java的动态类加载功能就是由类加载子系统完成的。类加载子系统在运...【详细内容】
2021-04-20  Tags: jvm  点击:(229)  评论:(0)  加入收藏
1:什么是JVMJVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java...【详细内容】
2021-04-12  Tags: jvm  点击:(251)  评论:(0)  加入收藏
背景目前,有很多公司的WEB服务器会出现CPU、内存、IO告警,运维人员往往不能及时地获取JVM等相关信息,以便分析造成告警的原因,故本文将从几个方面来阐述如何进行JVM快照,如何分析...【详细内容】
2021-03-12  Tags: jvm  点击:(168)  评论:(0)  加入收藏
平时开发的项目,有的是打成一个war包,放到tomcat这样的容器里运行。或者是打成一个jar包,通过java -jar 的方式去运行。大家有没有想过我们的项目是如何运行的呢?首先编译器会把...【详细内容】
2021-01-22  Tags: jvm  点击:(170)  评论:(0)  加入收藏
1 类加载器在类加载器家族中存在着类似人类社会的权力等级制度:1.1 Bootstrap由C/C++实现,启动类加载器,属最高层,JVM启动时创建,通常由与os相关的本地代码实现,是最根基的类加载...【详细内容】
2021-01-20  Tags: jvm  点击:(192)  评论:(0)  加入收藏
Thread Dump介绍Thread Dump是非常有用的诊断Java应用问题的工具。每一个Java虚拟机都有及时生成所有线程在某一点状态的thread-dump的能力,虽然各个 Java虚拟机打印的thread...【详细内容】
2021-01-18  Tags: jvm  点击:(170)  评论:(0)  加入收藏
什么是 Java 虚拟机(JVM)中的垃圾收集(GC)日志、线程转储和堆转储?Java 虚拟机(JVM)生成3个关键文件,这些文件对于JVM优化性能和解决生产问题非常有用。这些文件是: (GC) Garb...【详细内容】
2021-01-13  Tags: jvm  点击:(162)  评论:(0)  加入收藏
▌简易百科推荐
面向对象的特征之一封装 面向对象的特征之二继承 方法重写(override/overWrite) 方法的重载(overload)和重写(override)的区别: 面向对象特征之三:多态 Instanceof关键字...【详细内容】
2021-12-28  顶顶架构师    Tags:面向对象   点击:(2)  评论:(0)  加入收藏
一、Redis使用过程中一些小的注意点1、不要把Redis当成数据库来使用二、Arrays.asList常见失误需求:把数组转成list集合去处理。方法:Arrays.asList 或者 Java8的stream流式处...【详细内容】
2021-12-27  CF07    Tags:Java   点击:(3)  评论:(0)  加入收藏
文章目录 如何理解面向对象编程? JDK 和 JRE 有什么区别? 如何理解Java中封装,继承、多态特性? 如何理解Java中的字节码对象? 你是如何理解Java中的泛型的? 说说泛型应用...【详细内容】
2021-12-24  Java架构师之路    Tags:JAVA   点击:(5)  评论:(0)  加入收藏
大家好!我是老码农,一个喜欢技术、爱分享的同学,从今天开始和大家持续分享JVM调优方面的经验。JVM调优是个大话题,涉及的知识点很庞大 Java内存模型 垃圾回收机制 各种工具使用 ...【详细内容】
2021-12-23  小码匠和老码农    Tags:JVM调优   点击:(11)  评论:(0)  加入收藏
前言JDBC访问Postgresql的jsonb类型字段当然可以使用Postgresql jdbc驱动中提供的PGobject,但是这样在需要兼容多种数据库的系统开发中显得不那么通用,需要特殊处理。本文介绍...【详细内容】
2021-12-23  dingle    Tags:JDBC   点击:(13)  评论:(0)  加入收藏
Java与Lua相互调用案例比较少,因此项目使用需要做详细的性能测试,本内容只做粗略测试。目前已完成初版Lua-Java调用框架开发,后期有时间准备把框架进行抽象,并开源出来,感兴趣的...【详细内容】
2021-12-23  JAVA小白    Tags:Java   点击:(11)  评论:(0)  加入收藏
Java从版本5开始,在 java.util.concurrent.locks包内给我们提供了除了synchronized关键字以外的几个新的锁功能的实现,ReentrantLock就是其中的一个。但是这并不意味着我们可...【详细内容】
2021-12-17  小西学JAVA    Tags:JAVA并发   点击:(11)  评论:(0)  加入收藏
一、概述final是Java关键字中最常见之一,表示“最终的,不可更改”之意,在Java中也正是这个意思。有final修饰的内容,就会变得与众不同,它们会变成终极存在,其内容成为固定的存在。...【详细内容】
2021-12-15  唯一浩哥    Tags:Java基础   点击:(17)  评论:(0)  加入收藏
1、问题描述关于java中的日志管理logback,去年写过关于logback介绍的文章,这次项目中又优化了下,记录下,希望能帮到需要的朋友。2、解决方案这次其实是碰到了一个问题,一般的情况...【详细内容】
2021-12-15  软件老王    Tags:logback   点击:(19)  评论:(0)  加入收藏
本篇文章我们以AtomicInteger为例子,主要讲解下CAS(Compare And Swap)功能是如何在AtomicInteger中使用的,以及提供CAS功能的Unsafe对象。我们先从一个例子开始吧。假设现在我们...【详细内容】
2021-12-14  小西学JAVA    Tags:JAVA   点击:(21)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条