C++实现垃圾回收器(GC)

在.net中,不必考虑内存问题,因为有垃圾回收机制,但是在C++中,必须靠程序员释放申请的内存空间,如果操作不得当,很有可能会内存泄漏。
下面将写一个类,只要继承这个类,在合适的位置使用GC::instance.collect();就可以批量delete已申请的内存,如果有一些内存不需要释放可以添加例外GC::instance.pin(p2);,使用GC::instance.unpin§;可以恢复内存自动释放,使用也很简单,如果手动delete内存了,将不再delete:
//gc.h

#if !defined(GC_H)
#define GC_H

#include <set>
#include <map>

// For thread safety  为了线程安全
//#define THREAD_SAFETY 1

#if THREAD_SAFETY
#include <mutex>
#define MUTEXT_LOCK mMutex.lock()
#define MUTEXT_UNLOCK mMutex.unlock()
#else
#define MUTEXT_LOCK 
#define MUTEXT_UNLOCK 
#endif

// Base class for all objects that are tracked by
// the garbage collector.
//垃圾收集器跟踪的所有对象的基类。
class GCObject
{
public:

	// For mark and sweep algorithm. When a GC occurs
	// all live objects are traversed and mMarked is
	// set to true. This is followed by the sweep phase
	// where all unmarked objects are deleted.
	// 用于标记和扫描算法。当GC发生时,将遍历所有活动对象,
	//并将mMarked设置为true。随后是扫描阶段,删除所有未标记的对象。
	bool mMarked;

public:
	GCObject();
	GCObject(GCObject const&);
	virtual ~GCObject();

	// Mark the object and all its children as live
	// 将对象及其所有子对象标记为活动
	void mark();

	// Overridden by derived classes to call mark()
	// on objects referenced by this object. The default
	// implemention does nothing.
	// 被派生类重写,以对该对象引用的对象调用mark()。默认实现不起作用。
	virtual void markChildren();

public:
	void* operator new(size_t size);
	void* operator new(size_t size, void* p);
	void operator delete(void *p);

protected:
	void* operator new[](size_t size);
	void operator delete[](void *p);
};

// Wrapper for an array of bytes managed by the garbage
// collector.
// 垃圾收集器管理的字节数组的包装器。
class GCMemory : public GCObject
{
public:
	unsigned char* mMemory;
	int   mSize;

public:
	GCMemory(int size);
	virtual ~GCMemory();

	unsigned char* get();
	int size();
};

// Garbage Collector. Implements mark and sweep GC algorithm.
// 垃圾收集器。实现标记和扫描GC算法。
class GC
{
public:
	// Global garbage collector object
	// 全局垃圾收集器对象
	static GC instance;

public:
	// A collection of all active heap objects.
	// 所有活动堆对象的集合。
	typedef std::set<GCObject*> ObjectSet;
	ObjectSet mHeap;

	// Collection of objects that are scanned for garbage.
	// 扫描垃圾的对象集合。
	ObjectSet mRoots;

	// Pinned objects
	// 固定的对象
	typedef std::map<GCObject*, unsigned int> PinnedSet;
	PinnedSet mPinned;

public:
	// Perform garbage collection. 
	// 执行垃圾收集。
	void collect();

	// Add a root object to the collector.
	// 将根对象添加到收集器。
	void addRoot(GCObject* root);
	// Remove a root object from the collector.
	// 从收集器中删除根对象。
	void removeRoot(GCObject* root);

	// Pin an object so it temporarily won't be collected. 
	// Pinned objects are reference counted. Pinning it
	// increments the count. Unpinning it decrements it. When
	// the count is zero then the object can be collected.
	// 固定对象,使其暂时不会被收集。
	// 固定对象被引用计数。锁定它
	// 增加计数。松开它会使它变小。当计数为零时,则可以收集对象。
	void pin(GCObject* o);
	void unpin(GCObject* o);

	// Add an heap allocated object to the collector.
	// 将堆分配的对象添加到收集器。
	void addObject(GCObject* o);
	// Remove a heap allocated object from the collector.
	// 从收集器中删除堆分配的对象。
	void removeObject(GCObject* o);

	// Go through all objects in the heap, unmarking the live
	// objects and destroying the unreferenced ones.
	// 遍历堆中的所有对象,取消标记活动对象并销毁未引用的对象。
	void sweep();

	// Number of live objects in heap
	// 堆中的活动对象数
	int liveCount();

protected:

#if THREAD_SAFETY
	std::mutex mMutex;
#endif

};

#endif

//gc.cpp

#include "gc.h"
#include <vector>

// GCObject
GCObject::GCObject()
	: mMarked(false)
{

}

GCObject::GCObject(GCObject const&)
	: mMarked(false)
{

}

GCObject::~GCObject()
{
}

void GCObject::mark()
{
	if (!mMarked)
	{
		mMarked = true;
		markChildren();
	}
}

void GCObject::markChildren()
{
}

void* GCObject::operator new(size_t size)
{
	void* p = ::operator new(size);
	GC::instance.addObject((GCObject*)p);
	return p;
}

void* GCObject::operator new(size_t size, void* p)
{
	return ::operator new(size, p);
}

void GCObject::operator delete(void *p)
{
	GC::instance.removeObject((GCObject*)p);
	::operator delete(p);
}

void* GCObject::operator new[](size_t size)
{
	void* p = ::operator new[](size);
	return p;
}

void GCObject::operator delete[](void *p)
{
	::operator delete[](p);
}

// GCMemory
GCMemory::GCMemory(int size)
	: mSize(size)
{
	mMemory = new unsigned char[size];
}

GCMemory::~GCMemory()
{
	delete[] mMemory;
}

unsigned char* GCMemory::get()
{
	return mMemory;
}

int GCMemory::size()
{
	return mSize;
}


// GarbageCollector
GC GC::instance;

void GC::collect()
{
	MUTEXT_LOCK;
	// Mark root objects
	for (ObjectSet::iterator it = mRoots.begin();
		it != mRoots.end(); ++it)
	{
		(*it)->mark();
	}

	// Mark pinned objects
	for (PinnedSet::iterator it = mPinned.begin();
		it != mPinned.end(); ++it)
	{
		(*it).first->mark();
	}
	MUTEXT_UNLOCK;

	sweep();
}

void GC::addRoot(GCObject* root)
{
	MUTEXT_LOCK;
	mRoots.insert(root);
	MUTEXT_UNLOCK;
}

void GC::removeRoot(GCObject* root)
{
	MUTEXT_LOCK;
	mRoots.erase(root);
	MUTEXT_UNLOCK;
}

void GC::pin(GCObject* o)
{
	MUTEXT_LOCK;
	PinnedSet::iterator it = mPinned.find(o);
	if (it == mPinned.end())
	{
		mPinned.insert(std::make_pair(o, 1));
	}
	else
	{
		(*it).second++;
	}
	MUTEXT_UNLOCK;
}

void GC::unpin(GCObject* o)
{
	MUTEXT_LOCK;
	do
	{
		PinnedSet::iterator it = mPinned.find(o);
		if (it == mPinned.end())
			break;

		if (--((*it).second) == 0)
			mPinned.erase(it);
	} while (0);
	MUTEXT_UNLOCK;
}

void GC::addObject(GCObject* o)
{
	MUTEXT_LOCK;
	mHeap.insert(o);
	MUTEXT_UNLOCK;
}

void GC::removeObject(GCObject* o)
{
	MUTEXT_LOCK;
	mHeap.erase(o);
	MUTEXT_UNLOCK;
}

void GC::sweep()
{
	std::vector<GCObject*> erase;

	MUTEXT_LOCK;
	for (ObjectSet::iterator it = mHeap.begin();
		it != mHeap.end(); ++it)
	{
		GCObject* p = *it;
		if (p->mMarked)
		{
			p->mMarked = false;
		}
		else
		{
			erase.push_back(*it);
		}
	}
	MUTEXT_UNLOCK;

	for (std::vector<GCObject*>::iterator it = erase.begin();
		it != erase.end(); ++it)
	{
		delete *it;
	}
}

int GC::liveCount()
{
	MUTEXT_LOCK;
	int nCount = mHeap.size();
	MUTEXT_UNLOCK;
	return nCount;
}

测试的例子

#include "gc.h"
#include <Windows.h>
#include <iostream>

class Test : public GCObject {
public:
	Test()
	{
		std::cout << __FUNCTION__ "构造函数"<< std::endl;
	}
	~Test()
	{
		std::cout << __FUNCTION__ "析构函数" << std::endl;
	}
};

class Test2 : public GCObject {
public:
	Test* mTest;

	virtual void markChildren() {
		mTest->mark();
	}

	Test2()
	{
		std::cout << __FUNCTION__ "构造函数" << std::endl;
	}
	~Test2()
	{
		std::cout << __FUNCTION__ "析构函数" << std::endl;
	}
};

class Test3 : public GCObject {
public:
	Test* mTest;

	virtual void markChildren() {
		mTest->mark();
	}

	Test3()
	{
		std::cout << __FUNCTION__ "构造函数" << std::endl;
	}
	~Test3()
	{
		std::cout << __FUNCTION__ "析构函数" << std::endl;
	}
};

class Test4 : public Test {
public:
	
	Test4()
	{
		std::cout << __FUNCTION__ "构造函数" << std::endl;
	}
	~Test4()
	{
		std::cout << __FUNCTION__ "析构函数" << std::endl;
	}
};

void t1()
{
	for (int i = 0; i < 100; ++i)
	{
		new Test;
		Sleep(20);
	}
}

void t2()
{
	for (int i = 0; i < 100; ++i)
	{
		new Test;
		Sleep(20);
	}
}

void t3()
{
	for (int i = 0; i < 100; ++i)
	{
		GC::instance.collect();
		Sleep(10);
	}
}

void main()
{
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
	_CrtSetBreakAlloc(0);

#if 0 //被pin后的对象将不会被自动回收
	{
		std::cout << "===Normal test===" << std::endl;

		Test* p = new Test;

		Test2* p2 = new Test2;
		p2->mTest = p;

		Test3* p3 = new Test3;
		p3->mTest = p;

		GC::instance.collect();
	}

	{
		std::cout << "===Test pin member ptr===" << std::endl;

		Test* p = new Test;
		GC::instance.pin(p);

		Test2* p2 = new Test2;
		p2->mTest = p;

		Test3* p3 = new Test3;
		p3->mTest = p;
				
		GC::instance.collect();
	}

	{
		std::cout << "===Test pin one child class===" << std::endl;

		Test* p = new Test;

		Test2* p2 = new Test2;
		GC::instance.pin(p2);
		p2->mTest = p;

		Test3* p3 = new Test3;
		p3->mTest = p;
				
		GC::instance.collect();
	}

	{
		std::cout << "===Test pin all child classes===" << std::endl;

		Test* p = new Test;

		Test2* p2 = new Test2;
		GC::instance.pin(p2);
		p2->mTest = p;

		Test3* p3 = new Test3;
		GC::instance.pin(p3);
		p3->mTest = p;

		GC::instance.collect();
	}
#endif

	{
		std::cout << "===Test unpin===" << std::endl;

		Test* p = new Test;
		GC::instance.pin(p);
		GC::instance.unpin(p);
		GC::instance.collect();
	}

	{
		std::cout << "===Test stack===" << std::endl;
		//测试栈
		Test t;
		GC::instance.collect();
	}
	
	{
		std::cout << "===Test Placement new===" << std::endl;

		Test* t = new Test;
		Test* p = new(t)Test;
		GC::instance.collect();
	}

	{
		std::cout << "===Test inherit===" << std::endl;

		Test4* p4 = new Test4;
		GC::instance.collect();
	}
	
	//不可以new数组
	//Test* parr = new Test[10];//这一句编译错误

#if THREAD_SAFETY
	{
		//多线程测试
		std::thread thread1(t1);
		std::thread thread2(t2);
		std::thread thread3(t3);
		thread1.join();
		thread2.join();
		thread3.join();
		GC::instance.collect();
	}
#endif

	system("pause");
	return;
}

下面是输出的结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq285503851

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值