再談讓C++更像C#:C#內(nèi)存泄露問題
前段時(shí)間寫了一篇日志叫《讓C++更像C#》,但我寫的那段示例代碼中的有關(guān)內(nèi)存泄漏的問題當(dāng)時(shí)我說先不管,其實(shí)是那時(shí)沒有找到很好的解決方法。不好解決C#內(nèi)存泄露的原因是,沒有辦法去判斷一個(gè)指針到底是指向堆內(nèi)存,還是指向棧內(nèi)存(windows系統(tǒng)沒有API來實(shí)現(xiàn)這樣的功能)。當(dāng)時(shí)google、baidu都搜遍了,沒有找到解決辦法。
現(xiàn)在,就進(jìn)一步研究這個(gè)C#內(nèi)存泄露的問題。
今天在看國外的一篇技術(shù)文章的時(shí)候,發(fā)現(xiàn)有人就在研究這個(gè)問題!他給出了一種解決辦法。首先把他介紹,操作系統(tǒng)會(huì)為每一個(gè)系統(tǒng)中運(yùn)行的線程分配一個(gè)數(shù)據(jù)結(jié)構(gòu)叫做TIB(Thread Information Block)或者叫TEB(Thread Enviroment BLock)。里面記錄了與某個(gè)線程相關(guān)的所有信息。當(dāng)然包括線程相關(guān)的堆棧地址信息。而堆棧的棧頂與?;贩謩e存放在FS寄存器的4與8位置處。所以他通過嵌入式匯編實(shí)現(xiàn)了判斷指針是棧指針,還是堆指針的方法。代碼如下:
- bool IsMemoryOnStack( LPVOID pVoid )
- {
- LPVOID dwStackTop = 0;
- LPVOID dwStackLowCurrent = 0;
- __asm
- {
- mov EAX, FS:[4]
- mov dwStackTop, eax
- mov EAX, FS:[8]
- mov dwStackLowCurrent, eax
- }
- if( pVoid < = dwStackTop && pVoid >= dwStackLowCurrent )
- {
- // The memory lie between the stack top and stack commited.
- return true;
- }
- // Pointer dosen't point to the stack
- return false;
- }
現(xiàn)在只需要把CTest可能引起內(nèi)存泄漏的函數(shù)修改為如下,就可以解決問題了:
- CTest(CTest* & t)
- {
- this->x=t->getX();
- if(!IsMemoryOnStack(t))
- {
- delete t;
- t=0;
- }
- }
這里使用指針引用的好處是在防止在釋放了指針的內(nèi)存后,用戶繼續(xù)訪問指針的內(nèi)存。
到此為止,問題全部解決了!印度的軟件行業(yè)確實(shí)是挺牛比的!
這樣,這個(gè)C#內(nèi)存泄露問題就解決了。有關(guān)TIB的技術(shù)參考為:
http://www.microsoft.com/msj/archive/S2CE.aspx
【編輯推薦】