在.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;
}
下面是输出的结果: