垃圾回收算法


一、引用计数 (Reference Counting)

原理:每个对象维护引用计数,当计数归零时释放内存。

C++示例:

#include <iostream>

class RefCounted {
    int count = 0;

public:
    void addRef() { count++; }
    void release() {
        if (--count == 0) {
            delete this;
        }
    }

protected:
    virtual ~RefCounted() = default; // 允许派生类析构
};

class MyObject : public RefCounted {
public:
    MyObject() { std::cout << "Created\n"; }
    ~MyObject() { std::cout << "Destroyed\n"; }
};

int main() {
    MyObject* obj = new MyObject();
    obj->addRef(); // 引用计数=1

    obj->addRef(); // 引用计数=2
    obj->release(); // 引用计数=1

    obj->release(); // 引用计数=0,触发析构
    return 0;
}

缺点:无法处理循环引用(如A引用B,B引用A)。

二、标记-清除 (Mark-Sweep)

原理:从根对象出发标记所有可达对象,清除未标记的。

C++示例:

#include <iostream>
#include <vector>

class GCObject {
    static GCObject* head;  // 全局对象链表
    GCObject* next = nullptr;
    bool marked = false;

public:
    GCObject() { // 添加到链表
        next = head;
        head = this;
    }

    virtual ~GCObject() {}

    virtual void markChildren() {} // 标记引用的子对象

    void mark() {
        if (marked) return;
        marked = true;
        markChildren(); // 递归标记子对象
    }

    static void sweep() {
        GCObject** curr = &head;
        while (*curr) {
            GCObject* obj = *curr;
            if (!obj->marked) {
                *curr = obj->next;
                delete obj;
            } else {
                obj->marked = false;
                curr = &obj->next;
            }
        }
    }
};

GCObject* GCObject::head = nullptr;

// 根对象集合
std::vector<GCObject*> roots;

class Node : public GCObject {
public:
    Node* child = nullptr;

    void markChildren() override {
        if (child) child->mark();
    }
};

int main() {
    // 创建对象图:root -> node1 -> node2
    Node* node1 = new Node();
    roots.push_back(node1);

    Node* node2 = new Node();
    node1->child = node2;

    // 执行垃圾回收
    for (auto root : roots) root->mark();
    GCObject::sweep();

    // 手动清除根(示例中未释放roots,实际需管理生命周期)
    return 0;
}

缺点:内存碎片化,需暂停程序运行(Stop-the-World)。

三、标记-整理 (Mark-Compact)

原理:标记后移动存活对象至内存一端,整理后释放剩余空间。

简化示例(通过句柄间接访问对象):

#include <vector>

class Object {
    // 假设所有对象通过Handle访问
};

class Handle {
    Object* ptr;

public:
    Object* get() const { return ptr; }
    void relocate(Object* new_ptr) { ptr = new_ptr; }
};

std::vector<Handle*> handles; // 所有句柄需注册

void compact(std::vector<Object*>& alive) {
    // 移动存活对象到新内存区域
    for (auto& handle : handles) {
        if (/* 对象存活 */) {
            Object* new_addr = /* 新地址 */;
            handle->relocate(new_addr);
        }
    }
    // 释放旧内存
}

缺点:对象移动需更新所有引用,实现复杂。

四、分代回收 (Generational)

原理:按对象存活时间分代(年轻代、老年代),优先回收年轻代。

简化示例

class Generation {
    std::vector<GCObject*> young;
    std::vector<GCObject*> old;

    void promote(GCObject* obj) {
        // 将对象从年轻代晋升到老年代
        old.push_back(obj);
    }

public:
    void collectYoung() {
        // 标记-清除年轻代
        for (auto obj : young) if (isRoot(obj)) obj->mark();
        sweep();
        // 晋升存活对象
        for (auto obj : young) if (obj->marked) promote(obj);
        young.clear();
    }
};

优点:减少扫描范围,提升效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值