垃圾收集(Garbage Collection GC)

Java垃圾回收与对象存活判断
本文详细介绍了Java中的垃圾回收机制,包括GC需要回收的内存、何时回收以及如何回收。讲解了引用计数和根搜索两种对象存活判断算法,并讨论了Java中不同类型的引用。此外,还阐述了对象从不可达状态到真正被回收的两次标记过程,以及finalize()方法在对象回收中的作用。

一、GC需要做的三件事

哪些内存需要回收?

什么时候回收?

怎么回收?

二、判断对象是否“已死”

“已死”对象:不会再通过任何途径被使用

1、引用计数算法

在对象中添加一个计数器,当被引用时加1,当引用失效时减1;计数器为0时就是不可能在被使用的

优点:实现简单、判定效率高

缺陷:无法解决对象间互相引用问题

使用:微软COM技术、使用ActionScript3的FlashPlayer、Python

2、根搜索算法

已一系列名为“GC roots”的对象为起点向下搜索,搜索走过的路径叫做引用链;当一个对象到GC Roots对象没有任何引用链(对象不可达),则认为此对象不可用。

上图中Object 5、6、7到GC Roots中无引用链,因此判定“已死”,然后进行回收

在java中,可以当做GC Roots对象的有:

  • 虚拟机栈(栈帧中的本地变量表)中的引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中的常量引用的对象
  • 本地方法栈中JNI(Native方法)的引用的对象

3、引用

在JDK1.2之前:如果reference类型的数据中存储的数值代表另一块内存的起始地址,就称这块内存代表着一个引用

在JDK1.2之后进行了补充:将引用分为强引用(Strong Reference)软引用(Soft Reference)弱引用(Weak Reference)虚引用(Phantom Reference),引用强度依次降低

  • 强引用:就是指代码中普遍存在的类似“Object obj = new Object();” 这类的引用,只要强引用存在,垃圾收集器永远不会回收被引用的对象
  • 软引用:用来描述一些还有用,但并非必须的对象。对于软引用关联着的对象,在系统将要发生内存溢出之前,会对此类引用进行第二次回收
  • 弱引用:用来描述非必须对象,当垃圾收集器工作时,无论内存是否够用,被引用的对象都会被回收掉
  • 虚引用:也称幽灵引用、幻影引用,最弱的一种引用关系。一个虚引用的存在,不会对其生存时间构成影响,也无法通过虚引用获得一个对象实例;为对象设立虚引用关联的唯一目的是就是在垃圾收集器进行收集时收到一个系统通知

4、生存还是“死亡”

在根搜索算法中不可达的对象,还不能最终确定“已死”状态。

真正确定对象已死,还需要至少经历两次标记过程:

1)、在根搜索算法中没有引用链,被标记一次并经历一次筛选,筛选的条件是此对象是否有必要执行finalize()方法;判断是否有必要执行finalize()方法有两个条件:已经执行过finalize()方法、对象没有覆盖finalize()方法则认为没必要执行

如果判断有必要执行finalize()方法,则把对象放入F-Queue队列中,并由稍后由虚拟机自动创建的低优先级的Finalizer线程去执行。

2)、稍后GC会对F-Queue中的对象进行第二次标记,如果对象要在finalize中拯救自己,只需要与引用链上的对象建立一个关联即可,并且会在第二次标记时被移出“即将回收”的集合,否则就嗝屁了。

 

 

 

 

 

### 垃圾回收器工作原理 垃圾回收器的主要目标是在程序运行期间自动管理和释放不再使用的内存。其基本思路是识别并回收那些不再可访问的对象所占用的空间。 #### 标记-清除算法 一种经典的垃圾回收策略被称为「标记-清除」(Mark-Sweep),该方法分为两个主要阶段: - **标记阶段**:遍历所有根节点(通常是栈中的引用),递归地标记所有可达对象。 - **清理阶段**:扫描堆空间,查找未被标记的对象,并将其对应的内存区域回收以供后续再利用[^4]。 此过程中,任何未能通过可达性分析的对象都将被认为是废弃的,进而得到处理。 ### 分代收集机制 为了提升效率,现代JVM采用分代假设理论设计了多级结构化的垃圾收集体系——即所谓的“世代模型”。这种架构下,新生代、老年代各自对应不同频率与方式的清扫动作: - 新生代(Young Generation)通常发生较为频繁的小规模回收事件(Minor GC)。由于大多数新创建的对象很快就会变得不可达,因此这部分内存会被快速周转。 - 当某些存活周期较长的对象经过多次年轻代GC后仍未被淘汰,则迁移到年老代(Old Generation)。针对后者开展的大范围整理行动称为Major/Mixed GC,这类操作相对少见却耗时更久[^1]。 值得注意的是,在Java 8之后版本里,原本用于存储类元数据信息的永久代已被替换成了名为Metaspace的新组件;当这个区域容量不足时同样会引起Full GC的发生[^3]。 ### C# 中的具体实践 对于.NET平台而言,开发者应当注意合理控制应用程序内的对象生命期长度,比如优先选用局部作用域内的临时实例而非长期存在的字段成员,以此降低因过度活跃而导致过早触发GC的风险。另外还需警惕诸如装箱/拆箱转换之类的潜在陷阱,它们可能会间接增加额外开销。最后一点就是务必谨慎对待事件处理器注册行为,防止因为遗漏解除绑定而造成隐性的泄露隐患[^2]。 ```csharp public class DisposableResource : IDisposable { private bool disposed = false; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); // Prevent finalizer from running again. } protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { // Free managed resources here... } // Release unmanaged resources here... disposed = true; } } ~DisposableResource() { // Finalizer as backup cleanup mechanism. Dispose(false); } } ``` 上述代码展示了如何正确实现`IDisposable`接口来确保托管及非托管资源都能得到有效处置[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值