GC(Garbage Collection) 垃圾收集

本文详细解析了Java垃圾回收机制中的引用计数算法、标记-清除算法、复制算法及标记-整理算法,深入理解每种算法的工作原理及优缺点。
 GC(Garbage Collection) 垃圾收集
        在堆中,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象有哪些还“存活”着,哪些已经“死去”
 1、引用计数算法:
                给对象中添加一个引用计算器,每当有一个地方引用它时,计算器值就加1;当引用失效时,计数器就减1;
        任何时刻计数器都为0的对象就是不可能再被使用的。
        这种算法判断效率很高,但是在Java却没有使用种进行管理内容,其中最主要的原因是它很难解决对象之间的
        相互循环引用的问题。
        简单的例子:
        
public class ReferenceCountingGC {
        public Object instance = null;
        private static final int _1MB = 1024 * 1024;
        private byte[] bigSize = new byte[2 * _1MB];
        punlic  static void testGC(){
                ReferenceCountingGC objA = new ReferenceCountingGC();
                ReferenceCountingGC objB = new ReferenceCountingGC();
                objA.instance = objB;
                objB.instance = objA;
                
                objA = null;
                objB = null;
                
                System.gc();
        }
        
        public static void main(String[] orgs){
                ReferenceCountingGC.testGC();
        }
}
objA.instance = objB,objB.instance = objA,除此之外,这两个对象再无任何的引用,实际上这两个对象已经不可能
再被访问,但是它们因为互相引用着对方,导致它们的引用计书都不为0,于是引用计数算法无法通知GC收集器回收它们。


2、标记 - 清除算法
        分为两个阶段:
                首先标记所有需要回收的对象,
                在标记完成后统一回收掉所有被标记的对象。
        该算法有两个缺点:
                一个是效率问题,标记和清除过程的效率都不高。
                另外一个是空间问题,标记清除之后产生大量不连续的内存碎片,空间碎片大多可能导致,当程序在以后的远行
                过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。


3、复制算法:
            将可用内存按内量划分为大小相等的两块,每一次只使用其中一块。当这一块内存用完了,就将还存活着的对象复制
        到另外一块上面,然后再把已使用过的内存空间一次清理掉。
            现在的商业虚拟机都用这种算法来回收新生代,将内存分为一块较大的Eden空间和两块较小的Survivo空间。每次使用
        Eden和其中的一块Survivor。当回收时,将Eden和Survivor中还存活着的对象一次性地拷贝到另外一块Survivor空间上,
        最后清理掉Eden获取刚才用过的Survivor的空间。
        缺点:默认情况下Eden:Survivor=8:1, 所以总会有100-(80+10)%的新生代内存会被浪费掉。
        
4、标记 - 整理算法(适用于存放生命周期较长对象的)
        标记过程与“标记 - 清楚”算法一样,但是继步骤不是直接对可回收对象进行清理,而是让
        所有存活的对象都向一段移动,然后直接清理掉端边界以外的内存。




        
### 垃圾回收器工作原理 垃圾回收器的主要目标是在程序运行期间自动管理和释放不再使用的内存。其基本思路是识别并回收那些不再可访问的对象所占用的空间。 #### 标记-清除算法 一种经典的垃圾回收策略被称为「标记-清除」(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]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值