gt;p=p1;
当程序执行离开作用域后,这两块内存并没有象我想象的那样被释放,而是一直保留在堆中,直到程序结束。我仔细分析造成这种现象的原因,发现了一个非常有趣的问题,我把它称之为互锁现象。
上面p1 所拥有的指针被两个灵巧指针所拥有,除p1外,还有p2所拥有的 test 类中的灵巧指针p,p2亦然。也就是说,这两块内存的指针的引用记数都为 2 。当程序执行离开作用域后,p1,p2被析构,使它们的引用记数都为1,此后再没有灵巧指针被析构而使它们的引用记数变为 0 ,因此它们将长期保留在堆中。这就象两个被锁住的箱子,其中每个箱子中都装着对方的钥匙,但却无法把彼此打开,这就是互锁现象。
可是如何解决呢?看来必须对它进行改进。同时,我也发现上面的方法不支持多线程。所以,我们改进后的方法不仅要解决互锁现象,而且还要支持多线程。下面是我改进后的方法:
首先是如何发现这种互锁现象。我们知道,互锁现象产生的根源在于拥有堆中内存的灵巧指针本身也存在于已分配的堆内存中,那么,如何发现灵巧指针是存在于堆中还是栈中就成了问题的关键。由此,我引入了一个新的类 CPtr,由它来管理用 new 分配的指针,而 CPtrManager 专门用来管理 CPtr。如下所示:
class CPtr
{
friend class CMark;
public:
int GetPtrSize(); file://得到用 new 分配指针的内存的大小
CMutex * GetCMutex(); file://用于线程同步
void * GetPtr(); file://得到用 new 分配的指针
CPtr();
virtual ~CPtr();
int GetCount(); file://得到引用记数
void AddAutoPtr(void * autoPtr,int AutoMark);//加入一个拥有该指针的灵巧指针
BOOL DeleteAutoPtr(void * autoPtr); file://释放一个灵巧指针的拥有权
void SetPtr(void * thePtr,int Size, int mark,int count=0); file://设置一个新的指针
void operator delete(void * p)
{
free(p);
}
void * operator new(size_t size)
{
return malloc(size);
}
private:
int m_mark; file://指针标志
int m_count; file://引用记数
void * m_ptr; file://分配的指针
int m_size; file://指针指向内存的大小
CPtrArray AutoPtrArray; file://存放拥有该指针的所有灵巧指针的指针数组
CUIntArray m_AutoMark; file://灵巧指针标志:0 in the stack; >0 =mark
CMutex mutex; file://用于线程同步
};
class CPtrManager
{
public:
int GetAutoMark(void * ptr); file://通过灵巧指针的指针,得到灵巧指针标志
CPtrManager();
virtual ~CPtrManager();
int GetMarkFromPtr(void * Ptr);
void *MallocPtr(size_t size);
BOOL bCanWrite();
void DeletePtr(int mark,void * Ptr);
void AddPtr(void *Ptr,int PtrSize);
static CPtrManager * GetPtrManager();
CPtr * GetCPtr(void * Ptr,int mark);//通过指针和指针标志得到存放该指针的 CPtr
private:
CPtrArray m_ptr; file://存放 CPtr 的指针数组
void* pCurrent;
unsigned int m_mark;
CUIntArray m_removed;
BOOL bWrite; file://在解决互锁现象的过程中,谢绝其它线程的处理
static CPtrManager * p_this;
CMutex mutex;//用于线程同步
CMarkTable myMarkTable;
void RemoveLockRes(); file://处理互锁内存
void CopyAllMark(); file://处理互锁现象前,先对所有的CPtr进行拷贝
static UINT myThreadProc(LPVOID lparm); file://处理互锁现象的线程函数
CWinThread* myThread;
void BeginThread()
{ myThread=AfxBeginThread(myThreadProc,this,THREAD_PRIORITY_ABOVE_NORMAL);}
};
Java语言灵巧指针与垃圾回收(5)
时间:2011-01-16
上面的应用中加入了灵巧指针的标志,其实,这个标志就等于该灵巧指针所存在的 |