性能测试之 JVM 异常说明和分析工具
StackOverflowError和OutOfMemoryError是JVM里的两种Error。每个运行时区域——程序计数器
、Java虚拟机栈、本地方法栈、Java堆、方法区、直接内存发生Error的原因和错误信息是不同的。
不是所有的StackOverflowError和OutOfMemoryError都需要调整参数,要做到正确分析、合理调整
常见异常说明
Java堆溢出
- 关键错误信息
java.lang.OutOfMemoryError:java heap space
-
排查思路
检查Java虛拟机的堆参数设置,与机器的内存对比,看看是否还有向上调整的空间。再从代码上检查是否存在某些对象生命周期过长、持有状态时间过长、存储结构设计不合理等情况,尽量减少程序运行期的内存消耗。 -
参数配置
-Xmx 最大堆大小 默认物理内存的1/64
-Xms 初始堆大小 默认物理内存的1/4(<1GB)
栈溢出
HotSpot虚拟机栈=虚拟机栈+本地方法栈
- 错误信息
java.lang.StackOverflowError
java.lang.OutOfMemoryError
- 排查思路
出现StackOverflowError异常时,会有明确错误堆栈可供分析,相对而言比较容易定位到问题所在。
如果是建立过多线程导致的OutOfMemoryError,在不能减少线程数量或者更换64位虚拟机的情况下,就只能通过减少最大堆和减少栈容量来换取更多的线程,通过“减少内存”的手段来解决内存溢出。 - 参数配置
-Xss 每个线程堆栈的大小。一般情况下256K是足够了。影响此进程中并发线程数大小等。
方法区溢出
- 错误信息
JDK1.7以前的错误信息
java.lang.OutOfMemoryError: PermGen space
- 排查思路
JDK1.7起,原本存放在永久代的字符串常量池被移至Java堆之中,所以在JDK7及以上版本,限制方法区的容量对该测试用例来说是毫无意义的。
在JDK1.8以后,永久代便完全退出了历史舞台,元空间作为其替代者登场。 - 参数配置
<= JDK1.6
-XX:PermSize
-XX:MaxPermSize
>= JDK1.8
-XX:MetaspaceSize
-XX:MaxMetaspaceSize 元空间最大值,默认是-1,即不限制,或者说只受限于本地内存大小。
直接内存溢出
- 错误信息
java.lang.OutOfMemoryError
- 排查思路
由直接内存导致的内存溢出,一个明显的特征是在HeapDump文件中不会看见有什么明显的异常情况,如果读者发现内存溢出之后产生的Dump文件很小,而程序中又直接或间接使用了
DirectMemory ( 典型的间接使用就是NIO),那就可以考虑重点检查一下直接内存方面的原因了。 - 参数配置
-XX:MaxDirectMemorySize 默认与Java堆最大值(由-Xmx指定)一致
JDK自带的分析工具
jps JVM Process Status Tool 显示指定系统内所有的HotSpot虚拟机进程
jinfo Configuration Info for Java 显示虚拟机配置信息
jmap JVM Memory Map 生成虚拟机的内存转储快照,生成heapdump文件
jhat JVM Heap Dump Browser 用于分析heapdump文件,它会建立一个HTTP/HTML服务器,让用户在浏览器上查看分析结果
jstat JVM Statistics Monitoring Tool 用于收集Hotspot虚拟机各方面的运行数据
jstack JVM Stack Trace 显示虚拟机的线程快照
jstat
可以显示本地或者远程虛拟机进程中的类加载、内存、垃圾收集、即时编译等运行时数据,在没有GUI图形界面、只提供了纯文本控制台环境的服务器上,是运行期定位虚拟机性能问题的常用工具。
-class
监视类加载、卸载数量、总空间以及类装载所耗费的时间
-gc
监视Java堆状况,包括Eden区、2个Survivor区、老年代、永久代等的容量,已用空间,垃圾收集时间合计等信息
-gccapacity
监视内容与-gc基本相同,但输出主要关注Java堆各个区域使用到的最大、最小空间
-gcutil
监视内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比
-gccause
与-gcutil功能--样,但是会额外输出导致上一次垃圾收集产生的原因
-gcnew
监视新生代垃圾收集状况
-gcnewcapacity
监视内容与-gcnew基本相同,输出主要关注使用到的最大、最小空间
-gcold
监视老年代垃圾收集状况
-gcoldcapacity
监视内容与-gcold基本相同,输出主要关注使用到的最大、最小空间
-gcpermcapacity
输出永久代使用到的最大、最小空间
-compiler
输出即时编译器编译过的方法、耗时等信息
-printcompilation
输出已经被即时编译的方法
jstack
可以生成虚拟机当前时刻的线程快照(-般称为threaddump或者javacore文件)。线程快照就是当前虚拟机内每-条线程正在执行的方法堆栈的集合,生成线程快照的目的通常是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间挂起等,都是导致线程长时间停顿的常见原因。线程出现停顿时通过jstack来查看各个线程的调用堆栈,就可以获知没有响应的线程到底在后台做些什么事情,或者等待着什么资源。
jstack -l 进程ID
除堆栈外显示关于锁的附加信息
扫一扫,关注我