System.gc()的工作原理

很多人把Java的“效率低下”归咎于不能自由管理内存,但我们也知道将内存管理封装起来的好处,这里就不赘述。

Java中的内存分配是随着new一个新的对象来实现的,这个很简单,而且也还是有一些可以“改进”内存回收的机制的,其中最显眼的就是这个System.gc()函数。

乍一看这个函数似乎是可以进行垃圾回收的,可事实并不是那么简单。
其实这个gc()函数的作用只是提醒虚拟机:程序员希望进行一次垃圾回收。但是它不能保证垃圾回收一定会进行,而且具体什么时候进行是取决于具体的虚拟机的,不同的虚拟机有不同的对策。

那么下一个问题就是:gc()进行回收的准则是什么?也就是说什么样的对象可以被回收?
简单来说就是:没有被任何可达变量指向的对象。这里的可达是我发明的……意思就是能够找到的,那什么样的是不可达的呢?
比如说:
a.v = b;
b.v = c;
/*
 *Watch out !
 */
a.v = d;
看一下这段代码:
第一行:对象a的变量v指向了对象b
第二行:对象b的变量v指向了对象c
第六行:对象a的变量v指向了变量d。
这个时候,虽然变量c指向的对象有c以及b.v指向它,但是它们都已经不可达了,为什么?因为唯一可以找到它们的是a.v,但是现在a.v指向了d,所以他们就是不可达的了。

理由也很直观:没有任何可达变量指向你,你还有活下去的理由吗?你就算活下去谁能找得到你呢?

所以说,C++中将释放了的指针置为null的习惯要保留到Java中,因为这有可能是你释放内存的唯一途径。

最后的箴言:不要频繁使用gc函数。
我的建议是:保持代码健壮(记得将不用的变量置为null),让虚拟机去管理内存。

<think> 我们正在详细解释GC(垃圾回收器)的工作原理,特别是针对Java虚拟机的垃圾回收机制。 注意:用户要求用中文回答,并在最后提出3-5个相关问题,且第一行必须是"§§相关问题§§"。 我们将按照以下结构回答: 1. 垃圾回收的基本概念 2. 垃圾回收的主要步骤(标记、清除等) 3. 不同的垃圾回收算法(如分代收集、标记-清除、标记-整理等) 4. 垃圾回收器的种类(如Serial, Parallel, CMS, G1, ZGC等)及其特点 然后,根据解释提出3-5个相关问题。 </think> ### **GC(垃圾回收)工作原理详解** --- #### **核心目标** 自动回收程序中**不再使用的堆内存**,避免内存泄漏。以Java的JVM为例: --- #### **工作流程** 1. **标记阶段(Marking)** - 遍历所有**GC Roots对象**(静态变量/活动线程/本地方法栈引用) - 递归标记所有**可达对象**(存活对象) ```java // 伪代码:标记过程 void mark(Object root) { if (root == null || root.isMarked) return; root.isMarked = true; for (Object ref : root.getReferences()) { mark(ref); // 深度优先遍历 } } ``` 2. **清除阶段(Sweeping)** - 回收所有**未标记对象**占用的内存 - 将内存块加入**空闲列表(Free List)** ```mermaid graph LR A[堆内存] --> B(标记存活对象) B --> C[遍历堆] C --> D{对象已标记?} D -->|是| E[保留] D -->|否| F[回收内存] ``` 3. **压缩阶段(Compacting - 可选)** - 移动存活对象**消除内存碎片** - 更新所有引用指针(需暂停应用线程) --- #### **关键机制** | **机制** | 作用 | 典型场景 | |--------------------|----------------------------------------------------------------------|------------------------------| | **分代收集** | 按对象年龄划分区域(新生代/老年代) | 新生代用复制算法回收频率高 | | **STW暂停** | 暂停所有应用线程保证标记准确性 | CMS的初始标记阶段 | | **并发标记** | GC线程与应用线程并行执行 | G1/ZGC的标记阶段 | | **写屏障** | 监控对象引用变更,避免漏标 | 增量式GC | | **最终化队列** | 被回收对象若有`finalize()`方法,延迟回收 | 不推荐使用的特性 | --- #### **主流回收器对比** | **回收器** | 工作模式 | 特点 | |------------|----------------|----------------------------------------------------------------------| | **Serial** | 单线程STW | 简单高效,适合客户端应用 | | **CMS** | 并发标记清除 | 低暂停时间,但会产生碎片 | | **G1** | 分区域回收 | 预测停顿时间,适合大堆内存(JDK9+默认) | | **ZGC** | 并发压缩 | <10ms超低暂停,支持TB级堆(JDK15+生产可用) | | **Shenandoah**| 并发回收 | 与ZGC竞争,RedHat主导开发 | --- #### **GC触发条件** 1. **新生代回收(Minor GC)** - Eden区空间不足 2. **老年代回收(Major GC)** - 老年代使用率超过阈值 3. **元空间回收** - 类加载器卸载时回收类元数据 4. **显式调用** - `System.gc()`(不保证立即执行)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值