date: 2020-03-18
本文参考自网络上多篇博客,并个人归纳总结,故此处不一一列举。
主要对一种 JVM 进行概况。
GC主要分为Minor GC和Major GC,它们又被称为Young GC和Full GC。前者主要针对Heap中的Young Gen,而后者针对Young Gen和Old Gen等区域。
在每一次 GC 之后,在此次 GC 中存活的对象 age 加1,age过大时对象会进入Old Gen。
Heap 区域线程共享,它是 GC 的重点管理对象,其分为 Young Gen 和 Old Gen。其中 Young Gen 存放存活时间较短和较小的对象,Old Gen 则存放存活时间较长或者较大的对象。(注意“和”与“或”的用法)
Young Gen 分为 Eden Space (伊甸园) 和 Survivor Space (幸存者区)。Eden Space 存放新创建的对象,并在 GC 后将所有未被回收的对象移至 Survivor Space 中的 To Survivor 区域中。
Survivor Space 划分为两个等大的区域:To Survivor 和 From Survivor。From Survivor 存放未被回收且未被移至 Old Gen 的对象,在 GC 之后将剩余的所有未被回收的对象移至 To Survivor 中。而 To Survivor 在 GC 之前一直保持 empty,在 GC 之后存放来自 Eden Space 和 From Survivor 的未被回收的对象。最后 To Survivor 和 From Survivor 会互换标识,这样使得相应标识的区域一直保持相同的功能,即使它的内存区域一直在变化。
Old Gen 中存放的是 Young Gen 中经过多次垃圾回收仍然存活的对象和 Young Gen 分配不了内存的大对象。在 Old Gen 存放满之后会触发 JVM 进行 Major GC。
个人认为这样设计的原因是,Minor GC 对运算资源的消耗比较少,所以可以通过多次的 Minor GC 尽可能地回收不需要的内存空间,节约内存资源。而经过多次 Minor GC 依旧存活的对象可能在未来很长一段时间内都不会被回收,所以就将其移入 Old Gen 中,等待 Old Gen 满时进行一次大规模的内存回收,避免其一直在 Young Gen 内增加 Minor GC 执行时所需的运算资源。
Method Area 线程共享,它一般存放类的信息、常量、静态变量、即时编译器编译的代码等。其中常量存放在 Runtime Constant Pool (运行时常量池) 中。
以前它是位于 Perm Gen (永久代) 中,但现在 Perm Gen 已经被逐渐拆分并取代,取而代之的是 Meta Space (元空间)。
PC Register 线程私有,用于执行一个 Java Method 时记录正在执行的虚拟机字节码指令的地址,在执行 Native Method 时它的值为 undefined。它是 JVM 中最小的一块内存区域,也是唯一一个在 Java 虚拟机规范中没有规定任何 OutOfMemoryError 情况的区域。
JVM Stack 线程私有,它的生命周期和线程一致。
Java 方法在执行时会在 JVM Stack 中入栈一个 Stack Frame (栈帧),方法结束时出栈。这个栈帧中存放着以下数据:
同时它会在线程请求的栈深度大于虚拟机所允许的深度时会出现StackOverflowError,而在 JVM Stack 可以动态扩展,但扩展时无法申请到足够的内存时出现OutOfMemoryError。
类似 JVM Stack,同样是线程私有的。但它服务于 Native Method,同时也具有 StackOverflowError 和 OutOfMemoryError。
使用本地内存,其取代 Perm Gen (永久代) 存放类相关的元数据。
它通过调用本地方法直接分配 JVM 之外的内存,可以通过 DirectByteBuffer 对象直接操作该内存,同时存在 OutOfMemoryError。
原文:https://www.cnblogs.com/wilfredshen/p/12853936.html