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.