定位生产问题时,异常堆栈莫名丢了,何解?
今天分享的这个知识有点冷,相信很多 Java 程序员很少遇到,废话不多说,直接进入排查问题的真实讨论现场。
小 猿:有个 NPE 异常,有空帮忙看看是哪里出的?
架构狮:我没有看到空指针堆栈啊!?
小 猿:有堆栈我就自己找问题了,就不劳驾您老啦(捂嘴笑)。
架构狮:是不是 NPE 报了好多次?
小 猿:是。
架构狮:一猜就是,因为只有报了很多次,Java 才会自动不打印异常堆栈信息(言外之意:报了多了 java 会省略的),那就找找最开始报异常的日志,肯定会有堆栈信息的(哈哈,心里有谱啦),这种机制叫做 fast throw。
1
异常堆栈信息丢了?
只见 Java 攻城狮小猿傻傻的盯着业务日志,一脸呆萌... ...
[2020-08-15 00:00:00]: 668812118 Thread-8 [ERROR] payService:java.lang.NullPointerException
与其傻傻迷思,不妨直接来个现场说法,talk is cheap,show me the code,直接上代码。
/**
* Fast Throw 知识点分享
* @author 一猿小讲
*/
public class NPETest {
public static void main(String[] args) {
String msg = null;
for (int i = 0; i < 1000000; i++) {
try {
// msg 为空,会出现空指针异常
System.out.println(msg.length());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
程序刚开始跑的时候,程序输出是下面这样子的。
java.lang.NullPointerException
at NPETest.main(NPETest.java:11)
... ...
java.lang.NullPointerException
at NPETest.main(NPETest.java:11)
一会儿的功夫,输出却变成下面这个样子,异常堆栈确实丢了。
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
架构狮:惊奇不?有没有匪夷所思。
小 猿:何解?
架构狮:这种现象就叫做 fast throw,是 Java 虚拟机的一个优化,如果发现代码同一个位置频繁抛出同一类型的异常时,异常堆栈信息就会被清空,那么速度就会非常快,就不用再额外分配内存。
到这儿,Java 攻城狮小猿,点了一根香烟,感觉受益颇深,不过却又陷入了沉思。
2
Fast Throw 深入一点,又何妨?
思考一:查问题也太不方面了,如何让异常堆栈信息展示呢?
首先要清楚,JVM 会默认开启 Fast Throw 优化。如果想关闭这个优化,通过配置 -XX:-OmitStackTraceInFastThrow 就可以。
接下来还是跑上面 NPETest 的例子,配置 VM 参数,一起操作一把。
IDEA 运行时指定参数:-XX:-OmitStackTraceInFastThrow。
控制台运行时指定参数:
java -XX:-OmitStackTraceInFastThrow NPETest
效果很明显,异常堆栈信息一直坚挺到最后:
... ...
java.lang.NullPointerException
at NPETest.main(NPETest.java:11)
java.lang.NullPointerException
at NPETest.main(NPETest.java:11)
java.lang.NullPointerException
at NPETest.main(NPETest.java:11)
话又说来,如何再开启 fast throw 优化呢?
方式一:默认就是开启优化;
方式二:-XX:+OmitStackTraceInFastThrow
思考二:除了 NPE 异常,JVM 开启 fast throw 优化的异常还有哪些?
- ArithmeticException
- ArrayIndexOutOfBoundsException
- ArrayStoreException
- ClassCastException
烟味灭,酒过半,Java 攻城狮小猿彻底掌握了技巧,嘴角洋溢着笑容,此番操作不但解决了生产问题,而且又 get 一装逼技能... ...
3
寄语写最后
本次,主要对小猿在排查生产上遇到的一个匪夷所思的问题,作为基础进行展开,简单对 JVM 特定类型的异常的 fast throw 优化进行了解,希望对大家有帮助。
- GreenPlum 简单性能测试与分析(续)
- 最终版 Reflector v1.0 (+简单的反流程混淆)
- 性能&分布式&NewLife.XCode对无限数据的支持
- ASP.NET MVC下的异步Action的定义和执行原理
- 包学会之浅入浅出Vue.js:结业篇
- 迈克尔•戴尔:人工智能杀手?技术反乌托邦?不存在的
- 你知道吗?多个类多线程环境下静态构造函数的执行顺序
- 云端架构师养成之三:微信也在用的消息队列服务
- 现在 tensorflow和mxnet 很火,是否还有必要学习 scikit-learn 等框架?
- ASP.NET MVC基于标注特性的Model验证:将ValidationAttribute应用到参数上
- 改进版CodeTimer及XCode性能测试
- 常见测试术语解析
- 秦俊:开放 DevOps 敏捷开发套件,助力开发者驰骋云端
- 开源组件NanUI一周年-使用HTML/CSS/JS来构建.Net Winform应用程序界面
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Linux查看某个端口的连接数的方法
- 浅析Linux中使用nohup及screen运行后台任务的示例和区别
- 快速搭建简易、高效、多线程http服务器
- Linux解压文件到指定目录的方法
- Linux系统中CPU占用率较高问题排查思路与解决方法
- linux中ftp服务搭建需要注意的地方
- CentOS下使用LibreOffice实现文档格式的转换方式
- 详解在Linux中怎么使用cron计划任务
- Linux系统删除文件夹和文件的命令
- 详解Linux防火墙iptables禁IP与解封IP常用命令
- 在Ubuntu 16.04 Server上安装Zabbix的方法
- Centos7.3安装部署最新版Zabbix3.4的方法(图文)
- Linux系统下移植busybox中mkfs.vfat命令
- Linux服务器配置ip白名单防止远程登录以及端口暴露的问题
- Ubuntu上释放空间的5种简单方法