日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

内存泄漏以及常见的解决方法

發(fā)布時間:2025/3/15 编程问答 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 内存泄漏以及常见的解决方法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

? 之所以撰寫這篇文章是由于前段時間花費了非常大的精力在已經(jīng)成熟的代碼上再去處理memory leak問題。寫此的目的是希望我們應(yīng)該養(yǎng)成良好的編碼習慣,盡可能的避免這種問題,由于當你對著一大片的代碼再去處理此類的問題,此時無疑添加了解決的成本和難度。準確的說屬于補救措施了。 1. 什么是內(nèi)存泄漏(memory leak)?

?指因為疏忽或錯誤造成程序未能釋放已經(jīng)不再使用的內(nèi)存的情況。內(nèi)存泄漏并不是指內(nèi)存在物理上的消失,而是應(yīng)用程序分配某段內(nèi)存后,因為設(shè)計錯誤,失去了對該段內(nèi)存的控制,因而造成了內(nèi)存的浪費。?

A memory leak is a particular type of unintentional memory consumption by a computer program where the program fails to release memory when no longer needed. This condition is normally the result of a bug in a program that prevents it from freeing up memory that it no longer needs.This term has the potential to be confusing, since memory is not physically lost from the computer. Rather, memory is allocated to a program, and that program subsequently loses the ability to access it due to program logic flaws.?

2. 對于C和C++這樣的沒有Garbage Collection 的語言來講,我們主要關(guān)注兩種類型的內(nèi)存泄漏:

?? 堆內(nèi)存泄(Heap leak)。對內(nèi)存指的是程序執(zhí)行中依據(jù)須要分配通過malloc,realloc new等從堆中分配的一塊內(nèi)存,再是完畢后必須通過調(diào)用相應(yīng)的 free或者delete 刪掉。假設(shè)程序的設(shè)計的錯誤導(dǎo)致這部分內(nèi)存沒有被釋放,那么此后這塊內(nèi)存將不會被使用,就會產(chǎn)生Heap Leak.?

? 系統(tǒng)資源泄露(Resource Leak).主要指程序使用系統(tǒng)分配的資源比方 Bitmap,handle ,SOCKET等沒有使用對應(yīng)的函數(shù)釋放掉,導(dǎo)致系統(tǒng)資源的浪費,嚴重可導(dǎo)致系統(tǒng)效能減少,系統(tǒng)執(zhí)行不穩(wěn)定。??

3. 怎樣解決內(nèi)存泄露?

內(nèi)存泄露的問題其困難在于1.編譯器不能發(fā)現(xiàn)這些問題。2.執(zhí)行時才干捕獲到這些錯誤,這些錯誤沒有明顯的癥狀,時隱時現(xiàn)。3.對于手機等終端開發(fā)用戶來說,尤為困難。以下從三個方面來解決內(nèi)存泄露:

第一,良好的編碼習慣,盡量在涉及內(nèi)存的程序段,檢測出內(nèi)存泄露。當程式穩(wěn)定之后,在來檢測內(nèi)存泄露時,無疑添加了排除的困難和復(fù)雜度。

使用了內(nèi)存分配的函數(shù),要記得要使用其想用的函數(shù)釋放掉,一旦使用完成。

Heap memory:

malloc\realloc ------? free

new \new[] ----------? delete \delete[]

GlobalAlloc------------GlobalFree?

要特別注意數(shù)組對象的內(nèi)存泄

???? MyPointEX *pointArray =new MyPointEX [100];

????? 其刪除形式為:

???? delete []pointArray?

Resource Leak :對于系統(tǒng)資源使用之前要細致看起用法,防止錯誤使用或者忘記釋放掉系統(tǒng)資源。

我們看MSDN上一個創(chuàng)建字體的樣例: ?RECT rect;

HBRUSH hBrush; FONT hFont; hdc = BeginPaint(hWnd, &ps); ?hFont = reateFont(48,0,0,0,FW_DONTCARE,FALSE,TRUE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Impact"));

SelectObject(hdc, hFont);? SetRect(&rect, 100,100,700,200);

SetTextColor(hdc, RGB(255,0,0));

DrawText(hdc, TEXT("Drawing Text with Impact"), -1,&rect, DT_NOCLIP);????

DeleteObject(hFont);?? ?EndPaint(hWnd, &ps);

?

假設(shè)使用完畢時候忘記釋放字體,就造成了資源泄漏。?

?? 對于基于引用計數(shù)的系統(tǒng)對象尤其要注意,由于僅僅有其引用計數(shù)為0時,該對象才干正確被刪除。而其使用過程中有其生成的新的系統(tǒng)資源,使用完成后,假設(shè)沒有及時刪除,都會影響其引用計數(shù)。

?IDNS *m_pDns//define a DNS object.

?? If(NULL == m_pDns)

{? ?? IEnv_CreateInstance (m_pEnv,AEECLSID_DNS,(void **) (&m_pDns))

? }

If(m_pDns) {

??? Char szbuff[256];

??? IDNS_AddQuestions(M_pDns,AEEDNSTYPE_A,ADDDNSCLASS_IN,szbuff);

??? IDNS_Start(m_pDns,this);

??? const AEEDNSResponse * pDnsResponse = NULL;

?? IDNS_GetResponse(pMe->m_pDns, &pDnsResponse);

…………………………………………………………

…………………………………………………………..

………………………………………………………..

}

DNS_Release(pMe->m_pDns);//當程序執(zhí)行到此時,其返回值不是0,是1,其含義是程序已經(jīng)產(chǎn)生內(nèi)存泄露了,系統(tǒng)已經(jīng)有一個由DNS所產(chǎn)生的內(nèi)核對象沒有釋放,而當這段代碼多次執(zhí)行之后,內(nèi)存泄露將不斷添加……..

m_pDns=NULL;

? }

看起來非常不直觀,細致分析就會發(fā)現(xiàn),對象pDnsResponse是從m_pDns產(chǎn)生新的object,所以m_pDns的引用計數(shù)會添加,因此在使用完pDnsResponse,應(yīng)該release 該對象使其引用計數(shù)恢復(fù)正常。 ? 對于資源,也可使用RAII,RAII(Resource acquisition is initialization)資源獲取即初始化,它是一項非常easy的技術(shù),利用C++對象生命周期的概念來控制程序的資源,比如內(nèi)存,文件句柄,網(wǎng)絡(luò)連接以及審計追蹤(audit trail)等.RAII的基本技術(shù)原理非常easy.若希望保持對某個重要資源的跟蹤,那么創(chuàng)建一個對象,并將資源的生命周期和對象的生命周期相關(guān)聯(lián).如此一來,就能夠利用C++復(fù)雜老練的對象管理設(shè)施來管理資源.(有待完好)?

例2:

Struct ITypeface *pTypeface;

if (pTypeface)

{

IANY_CreateInstance(g_pApplet->m_pIShell,AEECLSID_BTFETypeface,void**)& Typeface);

}

接下來我們就能夠從這個接口上面創(chuàng)建字體,比方

IHFont **pihf=NULL;

?? ITypeface_NewFontFromFile(ITypeface,……,&pihf).

?? ITypeface_NewFontFrommemory(ITypeface,……..,&pihf)

? ?ITypeface_NewFontFromClassID(IType,……,&pihf)

?

?? 可是要切記,這些字體在使用完畢后一定要release掉,否則最后 iTypeface的引用計數(shù)就是你最后沒有刪除掉的字體的個數(shù)。?

第二,重載? new 和 delete。這也是大家編碼過程中常用的方法。

以下給出簡單的sample來說明。

memchecker.h

structMemIns

{

??? void * pMem;

??? int m_nSize;

??? char m_szFileName[256];

??? int m_nLine;

??? MemIns * pNext;

};

classMemManager

{

public:

??? MemManager();

??? ~MemManager();

private:

??? MemIns *m_pMemInsHead;

??? int m_nTotal;

public:

??? static MemManager* GetInstance();

??? void Append(MemIns *pMemIns);

??? void Remove(void *ptr);

??? void Dump();

?

};

void *operatornew(size_tsize,constchar*szFile, int nLine);

void?operatordelete(void*ptr,constchar*szFile, int nLine);

?void?operatordelete(void*ptr);

void*operatornew[] (size_tsize,constchar*szFile,int nLine);

void?operatordelete[](void*ptr,constchar*szFile, int nLine);

void?operatordelete[](void *ptr);

?

memechecker.cpp

#include"Memchecher.h"

#include<stdio.h>

#include<malloc.h>

#include<string.h>

?

MemManager::MemManager()

{

??? m_pMemInsHead=NULL;

??? m_nTotal=NULL;

}

MemManager::~MemManager()

{

?

}

voidMemManager::Append(MemIns *pMemIns)

{

??? pMemIns->pNext=m_pMemInsHead;

??? m_pMemInsHead = pMemIns;

??? m_nTotal+= m_pMemInsHead->m_nSize;

?

}

voidMemManager::Remove(void *ptr)

{

??? MemIns * pCur = m_pMemInsHead;

??? MemIns * pPrev = NULL;

??? while(pCur)

??? {

??????? if(pCur->pMem ==ptr)

??????? {

???????????if(pPrev)

??????????? {

???????????????pPrev->pNext =pCur->pNext;

??????????? }

???????????else

??????????? {

???????????????m_pMemInsHead =pCur->pNext;

??????????? }

???????????m_nTotal-=pCur->m_nSize;

???????????free(pCur);

???????????break;

??????? }

??????? pPrev = pCur;

??????? pCur = pCur->pNext;

??? }

?

}

voidMemManager::Dump()

{

??? MemIns * pp = m_pMemInsHead;

??? while(pp)

??? {

??????? printf( "File is %s\n", pp->m_szFileName );

??????? printf( "Size is %d\n", pp->m_nSize );

??????? printf( "Line is %d\n", pp->m_nLine );

??????? pp = pp->pNext;

??? }

?

}

?

voidPutEntry(void *ptr,intsize,constchar*szFile, int nLine)

{

??? MemIns * p = (MemIns *)(malloc(sizeof(MemIns)));

??? if(p)

??? {

??????? strcpy(p->m_szFileName,szFile);

??????? p->m_nLine = nLine;

??????? p->pMem = ptr;

??????? p->m_nSize = size;

??????? MemManager::GetInstance()->Append(p);

??? }

}

voidRemoveEntry(void *ptr)

{

??? MemManager::GetInstance()->Remove(ptr);

}

?

?

void *operatornew(size_tsize,constchar*szFile, int nLine)

{

??? void * ptr = malloc(size);

??? PutEntry(ptr,size,szFile,nLine);

??? return ptr;

}

voidoperatordelete(void *ptr)

{

??? RemoveEntry(ptr);

??? free(ptr);

}

void?operatordelete(void*ptr,constchar * file, intline)

{

??? RemoveEntry(ptr);

??? free(ptr);

}

?

void*operatornew[] (size_tsize,constchar* szFile,intnLine)

{

??? void * ptr = malloc(size);

??? PutEntry(ptr,size,szFile,nLine);

??? return ptr;

}

?

void?operatordelete[](void *ptr)

{

??? RemoveEntry(ptr);

??? free(ptr);

}

?

void?operatordelete[](void*ptr,constchar*szFile,intnLine)

?{

轉(zhuǎn)載于:https://www.cnblogs.com/mengfanrong/p/4198664.html

總結(jié)

以上是生活随笔為你收集整理的内存泄漏以及常见的解决方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。