2013-12-23 75 views
0

有一條規則告訴local variables在調用函數結束後被刪除。爲什麼程序分配的內存不會減少?

我試圖調用的函數(在C++)

void DoIt() 
{ 
    double x[100000]; 
} 

和研究,在目前產生由一些KBytes由程序增加分配數組x存儲器時。但是在調用函數結束後,內存不會減少。另外功能delete給出運行時錯誤。

那麼,爲什麼在結束調用函數後程序分配的內存不會減少呢?有沒有辦法刪除像上面這樣的局部變量?

+0

你如何測量內存使用? – delnan

+2

你的測量可能有缺陷。 'x'被分配在堆棧上。你沒有(也不能用你顯示的代碼)調用刪除它。 – ixe013

+0

在任務管理器 - >進程 – Nurlan

回答

0

絕對使用新的和刪除任何大量的內存分配;假設任何超過1Kb的內容或任何可能使用超過1Kb內存的內容 - 如果這是進入類,則可能需要運行本地靜態變量來計算實例數(int my_class :: static_variable;)併爲該類的每個實例分配一個唯一的ID和一個內存分配標記,以便您可以跟蹤誰分配了內存,誰不分配內存,誰將分配內存 - 然後您將觀察Task中內存消耗的預期增加和減少經理;我離題了。與磁盤驅動器虛擬內存分配無關。

總體而言,使用像這樣的靜態大小的數組是非常不負責任的,當涉及到內存管理時,即使它保證不會有內存泄漏,本身,因爲很可能你贏了' t需要立即全部分配內存,除非您正在潛入循環遍歷數組中的每個條目。

2

由於您不初始化(或觸摸)陣列,因此您會發現內存使用量增加,這一點令人驚訝。另一方面,在任務管理器之後你看不到內存使用情況並不奇怪。不過,這並不值得擔心。

這是爲什麼?

當你像這樣聲明一個數組時,它具有自動存儲持續時間。這意味着堆棧上的空間被分配給它(從形式上說,C++語言不知道「堆棧」這樣的東西,但這就是所有實現的方式 - 至少我所聽說過的所有實現)都是這樣工作的。

分配棧上的空間只是一個指針遞減一些值。只要你不嘗試讀取或寫入指向的內存,你幾乎可以做任何事情指針沒有任何事情發生(當然,發生事情發生,但不是壯觀的事情)。

在較低級別上,內存以頁面(通常爲4千字節)進行管理,該頁面以某種不透明的方式將一定範圍的虛擬地址與一些訪問權限映射到物理RAM。操作系統確保你永遠不會知道這一點。現在,操作系統會故意將堆棧最後一頁之後的頁面設置爲無效訪問模式,因此無論您何時嘗試從該頁面讀取或寫入值,都會生成錯誤。當發生這種情況時,操作系統會檢查堆棧的最大大小是否被超過(在這種情況下,程序將被終止)。如果情況並非如此,操作系統會提交一個新頁面,將其添加到工作集中,並讓您的程序繼續。

這樣做的好處是,對於每個單獨的線程,您可以擁有非常多的線程和非常大的理論堆棧大小,但是您只需支付所使用的費用。

現在,當您分配一個數十萬個double s時會發生什麼情況,只是將堆棧指針向下移動一個800,000字節的值(假設double的「常規」大小爲8個字節)。如果您初始化陣列,或者如果您觸摸此數組之後聲明的任何其他變量,則表示將發生頁面錯誤,操作系統將被啓動並分配堆棧空間。 Process Explorer將顯示它。

一旦提交,它不會消失,任務管理器將繼續顯示它。但是,只要函數返回,堆棧指針就會彈出回到之前的位置,以便回收該內存。

請注意堆棧通常不會無限增長(通常情況下,它默認限制在兆字節左右)。因此,分配這種具有靜態存儲時間的巨大陣列通常不是一個好主意。


在Windows下,有這個一個專用名詞:保護頁
原則上,可能,但對於操作系統什麼時候是安全的沒有簡單的方法在不需要編譯器插入額外的系統調用的情況下丟棄這些頁面,並且在最壞的情況下簡單地保留頁面並將它們交換出來可以很好地工作並且更容易。

相關問題