跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

JVM内存模型与垃圾回收_JVM内存区域划分与GC回收机制详解

堆内存是GC唯一真正干活的地方,程序计数器、虚拟机栈、本地方法栈生命周期与线程绑定,无需GC;方法区(Metaspace)回收条件苛刻、收益低;99%回收任务由Heap承担,对象分配于新生代Eden区,经Minor GC存活后进入Survivor,达年龄阈值或超大对象直接晋升老年代;Full GC代价高,应避免过早晋升;Metaspace虽取代PermGen,但配置不当仍会OOM;判断对象可回收仅依赖可达性分析,非引用计数;G1回收器按Region分区回收,Mixed GC兼顾新老代,但非全自动,需合理调参。 堆内存是GC唯一真正干活的地方 程序计数器、 虚拟机 栈、本地方法栈这三块区域,生命周期和线程完全绑定,入栈出栈时机确定,根本不需要GC介入。方法区(JDK 8+ 是
Metaspace
)虽然理论上可回收废弃类和常量,但实际触发条件苛刻、收益极低,生产环境几乎不靠它减压。真正承担99%内存回收任务的,只有
Heap
—— 所有
new
出来的对象、数组都落在这儿,也是
OutOfMemoryError: Java heap space
的唯一来源。 新生代(
Young Generation
)默认占堆 1/3,含
Eden
(约80%)、
Survivor S0
和
S1
(各约10%),对象优先分配在
Eden
; 一次
Minor GC
后存活对象进入
Survivor
,每经历一次 GC 年龄+1,达
-XX:MaxTenuringThreshold
(默认15)后晋升老年代; 大对象(如超长字符串、大数组)若超过
-XX:PretenureSizeThreshold
(默认0,即禁用),会直接进老年代,避免在新生代反复拷贝; 老年代(
Old Generation
)主要靠
Full GC
回收,但代价高、停顿长,应尽量减少对象过早晋升。 Metaspace 已取代 PermGen,但配置不当照样 OOM JDK 8 彻底移除了永久代(
PermGen
),类元数据(类名、字段、方法签名、常量池等)改存本地内存,由
Metaspace
管理。这不是“不用管了”,而是换了一种溢出方式:
java.lang.OutOfMemoryError: Metaspace
。
-XX:MetaspaceSize
是初始触发 GC 的阈值(非最大值),设太小会导致频繁 GC;
-XX:MaxMetaspaceSize
必须显式设置(默认无上限),否则可能耗尽本地内存,拖垮整个系统; Spring Boot + CGLIB 动态代理 、热部署(如 DevTools)、OSGi 插件场景极易生成大量类,是
Metaspace
溢出高发区; 字符串常量 池(
String Table
)已从方法区移到堆中,所以
intern()
过多会撑爆堆,而非 Metaspace。 判断对象是否可回收,只看可达性分析,不是引用计数 JVM 不用引用计数法(
Reference Counting
),因为解决不了循环引用问题。所有主流实现都基于可达性分析(
Reachability Analysis
):以一组称为
GC Roots
的对象为起点,向下搜索引用链;任何对象到
GC Roots
不可达,即判定为可回收。 Eclipse导入Android或其他的JAVA项目的正确方法 WORD版 本文档主要讲述的是Eclipse导入Android或其他的JAVA项目的正确方法;希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看 下载
GC Roots
包括:正在执行的线程的栈帧中的局部变量、本地方法栈中 JNI 引用、方法区中类静态属性引用、方法区中常量引用; 即使对象重写了
finalize()
,也仅获得一次“复活”机会(且 JDK 9+ 已标记为废弃),不应依赖;
SoftReference
/
WeakReference
/
PhantomReference
的行为差异极大,比如缓存用
SoftReference
,监听对象销毁用
PhantomReference
,别混用; 使用
System.gc()
只是建议 JVM 执行 GC,不保证立即发生,生产环境禁止调用。 G1 回收器不是万能药,混合回收逻辑容易误判
G1
(Garbage-First)是 JDK 9 默认、JDK 10+ 唯一支持的默认 GC,主打可预测停顿时间(
-XX:MaxGCPauseMillis
),但它不是“全自动优化器”。它的核心是把堆划分为多个大小相等的区域(
Region
),并按垃圾密度排序回收。
G1
的
Mixed GC
阶段既清理部分
Young
区,也选几个垃圾最多的
Old
区一起回收——这意味着老年代碎片化仍存在,且不会像 CMS 那样彻底并发清理; 若
Humongous Region
(超大对象占用的连续 Region)过多,会引发频繁
Full GC
,此时需调大
-XX:G1HeapRegionSize
或控制对象大小;
-XX:G1MixedGCCountTarget
和
-XX:G1OldCSetRegionThresholdPercent
等参数影响混合回收节奏,盲目调参反而加剧波动; 小堆(Parallel GC 往往比
G1
更稳更快,别迷信“新就是好”。 真正卡住人的从来不是概念,而是
MetaspaceSize
忘设、
PretenureSizeThreshold
乱调、把
SoftReference
当强引用用、或者以为开了 G1 就不用看 GC 日志——这些细节不落地,模型再熟也没用。

相关文章