2011-07-03 31 views
14

內存泄漏的基本概念是代碼執行過程中新/刪除操作的不匹配,或者是由於錯誤的編碼實踐或者在刪除操作被跳過時發生錯誤的情況。不同的內存泄漏方式

但最近我在採訪中被問到了一個關於記憶可能泄漏的其他方式的問題。 我沒有回答。它是什麼?

回答

15

常見的動態內存的問題是:

new
  • 動態內存分配,而不是與delete重新分配。
  • 使用new[]進行動態內存分配並使用delete重新分配。
  • 動態內存分配new並用free取消分配。
  • 動態內存分配malloc並將其與delete解除分配。

除了內存泄漏/內存損壞近3個方案將導致可怕的Undefined Behavior

其他一些潛在的內存泄漏引起我能記得的情況是:

  • 如果一個指針,指向一個動態分配的內存區域被釋放之前被重新分配一個新的值,它會導致a dangling pointer和內存泄漏。

一個代碼示例:

char *a = new[128]; 
    char *b = new[128]; 
    b = a; 
    delete[]a; 
    delete[]b; // will not deallocate the pointer to the original allocated memory. 

- 指針在STL容器

更常見,經常遇到的情況是,存儲指針指向在STL容器中動態分配的類型。需要注意的是,STL容器只有在不是指針類型時纔會刪除包含的對象
在刪除容器本身之前,必須顯式遍歷容器並刪除每個包含的類型。不這樣做會導致內存泄漏。
Here是這種情況的一個例子。

- 非虛基類的析構問題

刪除指針至基礎類指向派生類的上堆任何動態分配的對象。這會導致未定義的行爲。

的代碼示例:

class MyClass 
{ 
    public: 
    virtual void doSomething(){} 
}; 
class MyClass2 : public MyClass 
{ 
    private: 
     std::string str; 
    public: MyClass2(std::string& s) 
    { 
     str=s; 
    } 
    virtual void doSomething(){} 
}; 

int main() 
{ 
    std::str hello("hello"); 
    MyClass * p = new MyClass2(hello); 
    if(p) 
    { 
     delete p; 
    } 
    return 0; 
} 

在本例中只有析構函數MyClass的::〜MyClass的()被調用和MyClass2 ::〜MyClass2()不會被調用。對於適當的解除分配一個需要,

MyClass::virtual ~MyClass(){} 

- 上的void指針調用delete

A碼例如:

void doSomething(void * p) 
{ 
    //do something interesting 
    if(p) 
     delete p; 
} 

int main() 
{ 
    A* p = new A(); 
    doSomething(p); 
    return 0; 
} 

void指針調用delete如在上面的例子,會導致內存泄漏和未定義的行爲。

+0

第一點和最後一點是相同的。它們只是不同的場景。 – iammilind

+0

不使用異常安全代碼(從「不正確」的解除銷燬中派生)。 http://www.civilnet.cn/book/kernel/Effective%20C++%20(Third%20Edition)/ch05lev1sec4.html –

+3

@iammilind:那麼一切都歸結爲同一點,唯一的一點,休息都是場景。 –

4

作爲一個面試問題,面試官可能一直在尋找比教科書新/刪除不匹配更廣泛的視角。

任何超出最後需要的記憶都可以被認爲是「泄漏的」。這個內存最終可以通過在代碼中進一步刪除來手動釋放,這使得這些泄漏是暫時的,而不是因爲新的/刪除操作符不匹配而遇到的永久性泄漏。在「泄漏」持續的時間內,淨效應是相同的。您正在將可用資源(內存)的數量減少到程序的其他部分。

在垃圾回收代碼中,如果繼續持有對不再需要的對象的引用,則認爲內存泄漏,從而阻止垃圾回收器回收它。如果你無限期地持有不需要的對象,你已經在垃圾回收代碼中創建了一個永久泄漏。

+0

據我所知java與引用..所以有一種方法在Java持有對象的引用,即使他們超出範圍之後..所以然後指責應該可用於垃圾收集不是嗎? – ashishsony

+0

在您的主要方法中,在靜態字段中,有幾個引用示例,如果您允許它們,它們將一直保留到執行結束。 –

+0

在Java中,常見的錯誤是忘記對象的引用,通常與偵聽器有關。比如說,window1正在偵聽window2,你從你的gui中刪除了window1,但是因爲window2仍然在它的偵聽器列表中包含對它的引用,所以它不會被gc-ed。解決這個問題的一個方法是使用WeakReference。 – Jirka

3
  1. 分配內存以 new/new[]/malloc和不釋放它
  2. 分配內存一些指針 和覆蓋它意外例如p = new int; p = new int[1];
  3. 在空中分配內存。即new int[100];cout<<(*new string("hello"))<<endl;
+0

相信我,我修正了內存泄漏,就像第3點(這是自定義的內存分配器功能而不是'new')。 – iammilind

1

碎片可能是導致內存不足的問題之一。 經過長時間的程序運行後,可能會導致內存碎片。

2

總是有我最喜歡的,「非泄漏內存泄漏」,你的程序正確保留指針指向分配的內存,但(無論何種原因)從來沒有真正得到各地的釋放它們指向的內存:

// Maybe not technically a memory leak, but it might as well be one 
static vector<const char *> strings; 

void StoreTheString(const char * str) 
{ 
    strings.push_back(strdup(str)); 
} 

這很煩人,因爲內存泄漏檢測程序不會將其識別爲內存泄漏(因爲指針仍然可以訪問),但是您的程序仍然會消耗內存直到它崩潰。

即使在像Java這樣的垃圾收集語言中也會出現這種問題。

+0

我認爲這是@Als指出的關於stl容器的東西......如果它們是feeded指針......當它們不佔用它們的所有權時它們不會刪除具體對象, – ashishsony

0

我用重載運算符new和delete貝姆垃圾收集器,併爲與它編譯任何類作品完美,但隨着的std :: string和一些STL容器可怕的失敗,以及即使變量是垃圾收集類的成員。有一些內存泄漏,直到我意識到它。謝天謝地,它提供了一個垃圾收集分配器。

另外我還記得一個自動駕駛的汽車,它是用Java編程的,但每20到40分鐘就會墜毀*。它收集了有關道路上遇到的各種樹木和垃圾碎片的物體檢測信息,將它們訂閱到某個隊列中......並且從不刪除它們。

*:看看我在那裏做了什麼:D