2009-06-08 98 views
5

我對與向量有關的內存管理感到困惑,並且可以用一些基本概念來解釋。C++內存管理和向量

我有一個使用大向量的程序。 我創建的載體與運營商,並在程序與年底釋放他們刪除讓內存回來。

我的問題是,如果程序崩潰或中止對什麼都原因,刪除線將被錯過,有沒有辦法恢復的內存,即使在這種情況下。

我也有一些其他的大型矢量,我沒有分配新的關鍵字。 我已經讀過,這些將在堆上創建,但無論如何都不需要解除分配,因爲內存管理是在'引擎蓋下'處理的。 但是我不確定這是怎麼回事,因爲每次運行程序時我都會丟失RAM。

所以我的第二個問題是,可以在不關鍵字創建矢量真正留給自己的設備和信任後自己清理,即使代碼被中止中旬流。

而且我想,剛剛跳出來的心是,如果載體是自動上堆上創建,爲什麼你會永遠使用關鍵字與他們的第三個問題? 感謝您的閱讀, ben

+2

通過「每次我跑我的程序的時候我失去RAM」你的意思或「我的可用RAM獲取即使我退出程序小「直到我退出程序我的可用內存變小」了,它變得更小了下一次我跑,直到有一天,我將完全沒有內存剩下「? – 2009-06-08 19:31:45

+0

我借調Max的問題​​。 Windows我相信實際上並沒有卸載已終止的程序,除非需要。這樣他們在第一次之後就開始更快。 – 2009-06-08 19:48:18

+0

「我想第三個問題剛剛想到,如果矢量是自動創建在堆上,爲什麼你會使用新的關鍵字?」 如果您需要將矢量傳遞到當前範圍之外的某個點,則只需執行此操作。這在實踐中比較少見。 – rlbond 2009-06-09 04:09:28

回答

13

我懷疑你的問題是關於標準::矢量< T>(相對於陣列T [])。

  1. 當您的應用程序因任何原因崩潰或中止時,操作系統將回收內存。如果不是,你正在使用一個真正難得的操作系統,並發現了一個錯誤
  2. 您需要區分矢量本身使用的內存和其包含的對象的內存。可以在堆中或堆棧上創建矢量,它爲其包含的元素分配的內存始終位於堆上(除非您提供自己的分配器來執行其他操作)。由矢量分配的內存由矢量的實現來管理,如果矢量被破壞(或者因爲它超出了堆棧中矢量的範圍,或者因爲你刪除了堆中的矢量),它的析構函數確保所有內存被釋放。
3

您程序創建的任何內存將在退出時被釋放。這是操作系統的一項功能,與您使用的編程語言無關。

「每次我運行我的程序我鬆散RAM」一定是由於一些其他影響 - 你怎麼測量?

至於爲什麼你會使用「新」 - 兩個原因:

  • 你想,當他們被釋放
  • 你希望他們當前函數退出後持續控制。
+1

與Tobias相同的評論。大多數嵌入式操作系統和許多RTOS在進程崩潰時不會清理資源。 – 2009-06-08 17:28:52

+0

+1指出許多人沒有意識到。虛擬內存管理員是奢侈品,通常被認爲是理所當然的。 – Void 2009-06-08 19:37:01

3

我想你說的是std :: vector而不是語言數組。

  1. 當一個程序崩潰,則OS恢復其存儲器
  2. 的std ::矢量釋放其分配內存。如果你正在存儲指針,它們不會被刪除。
  3. 向量被創建爲任何其他變量,它們不在堆中,因爲它們是向量。
4

是的你可以信任載體自行清理。

然而你不能相信東西矢量持有自己清理之後。需要清理的內容可能會在應用程序之外持續存在。如果它的記憶,這不是一個擔心。如果確保XML標籤全部關閉,那麼操作系統將無法爲您提供幫助。

例如,如果你有這樣的一些靠不住的鎖定對象的向量:

class CLock 
    { 
    public: 
     CLock() {} 
     ~CLock() {} 

     void Lock(...) {...} 

     void Unlock(...) {...} 
    }; 

    std::vector<CLock> myLockVec; 

如何將其完成時,你的時鐘的專有的矢量解開一切嗎? Vector的構建不瞭解鎖。

這本質上是相同的情況下具有指針的向量:

std::vector<int*> myIntVec; 

如何矢量知道哪些指針這裏已被刪除,NULL'd,以及哪些是真的嗎?也許有些已被刪除並設置爲您的特殊值0xdeadbeef,意思是刪除。

的點是向量沒有手段知道這個或知道其元素是指針或鎖或任何。他們只需要具有默認構造函數並且是可複製的,並且滿足向量對其元素的其他這樣的需求。

解決方案是可以肯定的,無論矢量HOLDS需要負責其清理。這叫做RAII - 資源分配是初始化,在這裏更重要的是資源銷燬是取消分配。通過上面的CLock示例,答案很明顯,一定要在完成時解鎖!

class CLock 
{ 
     ... 
     ~Clock() 
     { 
      if (locked) 
      { 
       Unlock(); 
      } 
     } 
} 

但是指針其實並不那麼明顯。解決方案是將指針包裝在smart_ptr類中。其中最多產的是boost family of smart poniters

class CSmartPointer<T> 
{ 
     CSmartPointer(T* rawPtr) 
     { 
     m_ptr = rawPtr; 
     } 

     ~CSmartPointer() 
     { 
     delete m_ptr; 
     } 
} 

附加功能得到了充分的指針如引用計數,但上面的例子應該給你的問題的性質的要點以及如何它的典型解決。

1

對於 「失去的記憶」,什麼@RichieHindie說。

對於第二個問題:

可以在沒有新的關鍵字創建載體真的留給自己 自己的設備和信任後自己清理即使代碼 中止中期流動

當程序正常終止(包括異常終止)確保析構函數執行(與關於那些靜態數據的一些狡辯 - 在理論上這些應該太運行,實際上,你可能偶爾會問題)時,p的足夠硬的碰撞rocess不能保證任何行爲 - 例如,一個kill -9保證儘快終止您的程序,沒有給它機會執行任何析構函數或任何其他。

8

不要使用new創建載體。只要把它們放在堆棧上。

載體的析構函數自動調用向量中的每個元素的析構函數。所以你不必擔心自己刪除對象。但是,如果您有一個指針向量,指針將引用的對象將被清除,而不是而不是。這是一些示例代碼。爲了清晰起見,我省略了大部分細節:

class HeapInt 
{ 
    public: 
     HeapInt(int i) {ptr = new int(i);} 
     ~HeapInt() {delete ptr;} 
     int& get() {return *ptr;} 
    private: 
     int* ptr; 
}; 

int main() 
{ 
    // this code DOES NOT leak memory 
    std::vector<HeapInt> vec; 
    for (int i = 0; i < 10; ++i) 
    { 
     HeapInt h(i); 
     vec.push_back(h); 
    } 
    return 0; 
} 

即使main()拋出異常,也不會丟失內存。但是,此代碼確實泄漏內存:

​​3210
2

一個我們兩個是在這裏有點糊塗了。

如果您使用的std ::向量,你不需要爲它的元素以手動分配內存。無論何時執行push_back(),都會自動分配額外空間。如果您因某種原因需要預先分配所有空間,則可以調用reserve()。無論哪種方式,當矢量被破壞時,內存都會自動釋放。

如果你正在做新的std ::向量,你得到一個指針向量。這與在任何其他班級上呼籲新人沒有什麼不同。你創建一個指向這個類的對象的指針,當你調用delete的時候它會被破壞。如果你不喜歡這種行爲,嘗試在堆棧上創建你的矢量。

1

的問候沒有提到,當你想使用「新」的另一種情況,在某些情況下,當一個向量是一個類的成員變量。 NULL可以用作額外的信號量,例如在按需創建期間;另外,如果向量用法稀疏地填充到類上,那麼甚至不創建一個,除非真正需要它將節省您的內存,代價是所有實例上額外的4字節懲罰以及指針間接引發的運行時間損失。