JVM基础 -- VirtualMachineError实例
VirtualMachineError有两个常见的实现类:StackOverflowError、OutOfMemoryError,本文将用代码分析几种情况的VirtualMachineError
JVM参数
| 内存区域 | 虚拟机栈 VM Stack |
堆 Heap |
方法区 Method Area |
|---|---|---|---|
| 共享/隔离 | 线程隔离 | 线程共享 | 线程共享 |
| 存放的数据 | 栈帧 Stack Frame | 对象实例/数组 | 类信息、常量、静态变量等数据 |
| 异常情况 | StackOverflowError OutOfMemoryError |
OutOfMemoryError | OutOfMemoryError |
| JVM参数 | -Xss | -Xms -Xmx |
-XX:PermSize -XX:MaxPermSize -XX:MetaspaceSize -XX:MaxMetaspaceSize |
注:在JDK8之前,
Hotspot JVM采用永生代(Permanent Generation)来实现方法区(Method Area),从JDK8开始,已经移除了永生代,使用Metaspace进行替代,相关连接请参考:
实例
VM Stack - StackOverflowError
代码
1 | public class VMStackSOF { |
运行结果
1 | java.lang.StackOverflowError |
分析
VM Stack是线程私有,当线程执行一个方法时,会在VM Stack上创建一个Stack Frame,VM Stack类似于Stack(FILO)的数据结构,最上层的Stack Frame即当前线程执行的方法- 方法
从调用到执行完成,对应着Stack Frame在VM Stack中从入栈到出栈的过程 - 由于
VM Stack的空间有限,当递归调用的深度过大,有可能会抛出StackOverflowError
Heap - OutOfMemoryError
代码
1 | public class HeapOOM { |
运行结果
1 | [GC[DefNew: 2542K->320K(3072K), 0.0030860 secs] 2542K->1392K(9920K), 0.0031220 secs] [Times: user=0.00 sys=0.01, real=0.01 secs] |
MAT分析
1. 当线程运行main方法时,list是在的`VM Stack`的`Current Stack Frame`定义的`强引用(Strong Reference)`,且为`GC ROOT`,哪怕JVM堆内存不足的时候,触发`Full GC`,也不会将其回收,最后导致`OutOfMemoryError`
2. 由GC日志可以看出,`新生代的Eden区`存有`2`个OOMObject对象,`老年代`存有`6`个OOMObject对象,已经无法再容纳新的OOMObject对象,抛出`OutOfMemoryError`
Interned Strings
Interned Strings(字面量)在JDK6会存储在PermGen,从JDK7开始存储在Java Heap,减少OOM和性能问题
JDK6 - PermGen
代码
1 | // JDK ➔ 6 |
运行结果
1 | [GC [DefNew: 17587K->784K(18432K), 0.0078576 secs] 17587K->1928K(59392K), 0.0078864 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] |
分析
String.valueOf(i++).intern()会在Heap(valueOf)和PermGen(intern)中分配存储空间,并返回引用到strings进行保存(强引用,不会被GC回收)- 从GC日志可以看出,
Full GC时,PermGen接近填满([Perm : 51199K->51199K(51200K)])
JDK8 - Heap
代码
1 | // JDK ➔ 8 |
运行结果
1 | [GC (Allocation Failure) [DefNew: 161762K->20480K(184320K), 0.4081917 secs] 161762K->108735K(593920K), 0.4082377 secs] [Times: user=0.31 sys=0.06, real=0.41 secs] |
分析
String.valueOf(i++).intern()会在Heap(valueOf)中分配存储空间,并返回引用到strings进行保存(强引用,不会被GC回收)- 从GC日志可以看出,
Full GC时,Old Gen接近填满(Tenured: 409599K->409599K(409600K))
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.











