2011-05-11 79 views
5

Helo, 我無法成功如何釋放內存後在哈希鍵刪除。當我從哈希中刪除密鑰時,內存不會被釋放,也不會手動調用GC.start。這是預期的行爲還是GC在從Hash刪除密鑰並且這些對象泄漏到某處時不釋放內存?我如何刪除Hash中的密鑰並在內存中取消分配?刪除密鑰後紅寶石哈希內存泄漏

實施例:

irb(main):001:0> `ps -o rss= -p #{Process.pid}`.to_i 
=> 4748 
irb(main):002:0> a = {} 
=> {} 
irb(main):003:0> 1000000.times{|i| a[i] = "test #{i}"} 
=> 1000000 
irb(main):004:0> `ps -o rss= -p #{Process.pid}`.to_i 
=> 140340 
irb(main):005:0> 1000000.times{|i| a.delete(i)} 
=> 1000000 
irb(main):006:0> `ps -o rss= -p #{Process.pid}`.to_i 
=> 140364 
irb(main):007:0> GC.start 
=> nil 
irb(main):008:0> `ps -o rss= -p #{Process.pid}`.to_i 
=> 127076 

PS:我使用紅寶石1.8.7。我也試過紅寶石1.9.2,但它不是更好。

+2

我不知道,但我想ruby正在彙集那些被重用的內存,這是一個非常標準的做事方式。 – falstro 2011-05-11 18:43:08

+0

如果有人可以複製Adam的代碼,但是顯示重複多次創建和刪除對象不會增加內存使用量,這有助於回答問題。 – 2011-05-11 23:42:32

+0

釋放內存:1000000.times {| i |一個|| = []; a [i.to_s] = i; @ a.delete(ⅰ); GC.start; p ObjectSpace.count_objects} – 2012-10-20 17:50:45

回答

1

對象應該被垃圾收集。如果你再次創建它們,這個過程不應該顯着增長,因爲它擁有所有的空白空間。但是,Ruby不會將該內存釋放回操作系統,因爲它假定將來可能需要多少內存。

這是一個相當簡單的解釋,但基本上,你所看到的是正常的。

6

Stackoverflow: How Malloc and Free Work

出於各種理由(在引文闡述了以上)幾乎沒有內存管理器釋放內存回操作系統。

爲了看到過程更改,Ruby解釋器的C部分中的底層mallocfree需要將主機操作系統返回內存。這不會發生,但在Ruby級別,對象已被GC化,並在解釋器中保存在本地的免費列表中。

2

至於是誰在做這個東西,時間長了很多語言的高級開發人員,這是我的想法:

雖然我想用匯編語言,例如C,當你的用意是好的,細粒度的開發商受控制的內存管理並不適合像Ruby,Python和Perl這樣的語言。

像Perl,Ruby和Python這樣的腳本語言讓我們免於內存管理的煩惱。這是我們喜歡它們的原因之一。如果我們有可用的記憶,他們將使用他們需要的東西來完成工作。內存管理控制的損失是對開發速度和易調試性的折衷;我們沒有它,也不需要擔心。如果我需要它,我將使用C或彙編語言。

至於假設它是內存泄漏,那麼,我認爲這有點幼稚或放肆。像你提到的內存泄漏將是一個重大的漏洞,並且,儘管有許多基於Ruby的應用程序和站點,但很久以前有人會注意到它。所以,當我看到一些沒有意義的東西時,作爲對自己的理智檢查,我總是認爲我先在代碼中做了錯誤的事情,然後我會看看我對某些事情是如何工作的假設,如果這些看起來很合理,我會去找其他有類似問題的人,看看他們是否有解決方案。而且,如果問題是該語言的核心問題,那麼我會深入研究源代碼或與一些核心開發人員交談,並詢問我是否對所看到的內容感到不滿。我之前發現了低級別的bug,但是他們一直是角落案例,在我提到任何事情之前我花了幾天的時間,因爲我不想像我的同行一樣提交bug報告馬上與Apple聯繫,然後發現這是他的代碼中的一個錯誤。

我關於將內存返回到釋放系統的總體思路是否會產生額外的開銷,這可能會在下一次浪費CPU週期的操作中發生逆轉,這種操作會導致語言無法承受的解釋和腳本編寫,因爲它們速度並不快作爲編譯語言開始。我認爲這種語言假定它需要重複分配一大塊內存是公平的,尤其是在使用像Ruby這樣的OO語言時。在這一點上,保持先前使用的內存是很有意義的。

而且,在大的計劃中,考慮到我們在我們的盒子裏有多少免費空間,分配1,000,000個這種大小的數組元素並不是很多的內存。我會更關心是否需要在內存中維護一個數組中的1,000,000個元素,並且會向同行推薦他們應該認真對待使用數據庫。你可能有一個合理的商業理由,把它全部放在RAM中。如果是這樣,主機上的RAM最大,你應該沒問題。

0

如果您運行兩次分配,可以或多或少地看到@digitalross。如果真的有這樣的內存泄漏,你會期望內存大小加倍,但是這並沒有發生。

[~]$ irb           rvm:[email protected] 
1.9.3p0 :001 > `ps -o rss= -p #{Process.pid}`.to_i 
=> 8148 
1.9.3p0 :002 > a = {} 
=> {} 
1.9.3p0 :003 > 1000000.times{|i| a[i] = "test #{i}"} 
=> 1000000 
1.9.3p0 :004 > `ps -o rss= -p #{Process.pid}`.to_i 
=> 101188 
1.9.3p0 :005 > 1000000.times{|i| a.delete(i)} 
=> 1000000 
1.9.3p0 :006 > `ps -o rss= -p #{Process.pid}`.to_i 
=> 90960 
1.9.3p0 :007 > GC.start 
=> nil 
1.9.3p0 :008 > `ps -o rss= -p #{Process.pid}`.to_i 
=> 93388 
1.9.3p0 :009 > `ps -o rss= -p #{Process.pid}`.to_i 
=> 93388 
1.9.3p0 :010 > 1000000.times{|i| a[i] = "test #{i}"} 
=> 1000000 
1.9.3p0 :011 > `ps -o rss= -p #{Process.pid}`.to_i 
=> 140088 
1.9.3p0 :012 > 1000000.times{|i| a.delete(i)} 
=> 1000000 
1.9.3p0 :013 > `ps -o rss= -p #{Process.pid}`.to_i 
=> 130880 
1.9.3p0 :014 > GC.start 
=> nil 
1.9.3p0 :015 > `ps -o rss= -p #{Process.pid}`.to_i 
=> 104256 

在第一運行結束時,處理報告的93388的存儲器大小,所述第二運行後它報告104256,大約只有在存儲器使用增加了10%。