JVM内存结构
根据Java虚拟机规范,JVM内存主要划分为以下区域:
- 年轻代(New Generation)
- 包括Eden空间,用于存放新创建的对象。
- Survivor区由两个相同大小的Survivor1和Survivor2组成,用于存放经过初次垃圾回收后仍然存活的对象,通过“ survivor-to-survivor ”的过程提升对象年龄,最终符合条件的对象会被移到年老代。
- 年老代(Tenured Generation)
- 存放从年轻代中经历多次垃圾回收仍然存活的对象。\
- 永久代/元数据区(Permanent Generation/Metaspace)
- 在Java 8及以后版本中,永久代被元数据区取代,用于存储类、方法等元数据信息。可通过
-XX:MetaspaceSize
和-XX:MaxMetaspaceSize
参数调整其大小。 - 在早期版本中,永久代大小推荐初始设置为128M,并预留30%的增长空间。
垃圾收集算法
JVM的垃圾回收基于“标记-清除”或其衍生算法,具体包括:
- Serial算法:单线程回收,适用于单CPU环境,执行时会暂停所有用户线程。
- Parallel算法(并行回收):多线程并行回收,适用于多CPU环境,回收时暂停用户线程,但多个线程并行工作加速回收过程。
- Concurrent算法(并发回收):多线程回收,与应用程序并发执行,减少暂停时间,适用于对响应时间敏感的应用。
垃圾回收触发条件
- 当年轻代空间(特别是Eden区)填满时,触发Minor GC,只清理年轻代。
- 当年老代或元数据区满时,触发Full GC,同时回收年轻代和年老代(或进行元数据区的清理)。
OutOfMemoryError异常
JVM在以下情况可能抛出OutOfMemoryError
异常:
- 年轻代、年老代或元数据区空间耗尽,且无法通过回收获得足够的空间。
- 即使JVM并未完全耗尽内存,但在连续几次GC后,回收的内存比例小于2%,且JVM花费超过98%的时间在GC上,表明内存已极度碎片化,无法有效利用。
此机制设计旨在允许程序在崩溃前有机会执行最后的操作,例如输出堆转储(Heap Dump),便于后续分析故障原因。