2015-10-03 36 views
20

我想了解何時將分配給Ruby堆的內存返回給操作系統。我明白,Ruby永遠不會返回分配給堆的內存,但我仍然不確定非堆內存的行爲。即那些不適合40字節RVALUE的對象。爲什麼Ruby程序不會將堆內存返回到操作系統?

考慮下面的程序分配一些大的字符串,然後強制一個主要的GC。

require 'objspace' 

STRING_SIZE = 250 

def print_stats(msg) 
    puts '-------------------' 
    puts msg 
    puts '-------------------' 
    puts "RSS: #{`ps -eo rss,pid | grep #{Process.pid} | grep -v grep | awk '{ print $1,"KB";}'`}" 
    puts "HEAP SIZE: #{(GC.stat[:heap_sorted_length] * 408 * 40)/1024} KB" 
    puts "SIZE OF ALL OBJECTS: #{ObjectSpace.memsize_of_all/1024} KB" 
end 

def run 
    print_stats('START WORK') 
    @data=[] 
    600_000.times do 
    @data << " " * STRING_SIZE 
    end 
    print_stats('END WORK') 
    @data=nil 
end 

run 
GC.start 
print_stats('AFTER FORCED MAJOR GC') 

在MRI上運行該程序與Ruby 2.2.3它會產生以下輸出。在強制執行主GC之後,堆大小與預期的一樣,但RSS沒有顯着下降。

------------------- 
START WORK 
------------------- 
RSS: 7036 KB 
HEAP SIZE: 1195 KB 
SIZE OF ALL OBJECTS: 3172 KB 
------------------- 
END WORK 
------------------- 
RSS: 205660 KB 
HEAP SIZE: 35046 KB 
SIZE OF ALL OBJECTS: 178423 KB 
------------------- 
AFTER FORCED MAJOR GC 
------------------- 
RSS: 164492 KB 
HEAP SIZE: 35046 KB 
SIZE OF ALL OBJECTS: 2484 KB 

將這些結果與分配一個大對象而不是許多較小對象時的以下結果進行比較。

def run 
    print_stats('START WORK') 
    @data = " " * STRING_SIZE * 600_000 
    print_stats('END WORK') 
    @data=nil 
end 

------------------- 
START WORK 
------------------- 
RSS: 7072 KB 
HEAP SIZE: 1195 KB 
SIZE OF ALL OBJECTS: 3170 KB 
------------------- 
END WORK 
------------------- 
RSS: 153584 KB 
HEAP SIZE: 1195 KB 
SIZE OF ALL OBJECTS: 149064 KB 
------------------- 
AFTER FORCED MAJOR GC 
------------------- 
RSS: 7096 KB 
HEAP SIZE: 1195 KB 
SIZE OF ALL OBJECTS: 2483 KB 

請注意最終的RSS值。我們似乎已經釋放了我們爲大字符串分配的所有內存。

我不確定爲什麼第二個示例會釋放內存,但第一個示例並不如此,因爲它們都是從Ruby堆中分配內存。這是一個reference,可以提供解釋,但我會對其他人的解釋感興趣。

將內存釋放回內核也會產生成本。用戶空間內存 分配器可能會保留該內存(私下),希望它可以在相同的進程內重新使用 ,並且不會將其返回到內核,以便在其他進程中使用 。

+1

訂閱此線程。我對此也很感興趣。 – dimitarvp

+1

最基本的區別在於第一個示例,其中創建了600k *個新對象,僅次於第二個對象。雖然*引用*數據的總大小是相同的,但第一個示例需要60萬次以上的引用對象的時隙(可能永遠不會或稍後回收到操作系統)。 – joanbm

+2

我會建議以下[文章](http://www.sitepoint.com/ruby-uses-memory/)和鏈接[解釋](http://rocket-science.ru/hacking/2013/12/17/ruby​​-memory-pitfalls /)'RVALUE's。我不確定他們是否正確,只有Koichi aka ko1自己可能知道。或者是一些堅定不移的愛好者,分析Ruby的來源。 – joanbm

回答

1

@joanbm在這裏有一個很好的觀點。他的引用是article explains this pretty well

Ruby的GC逐漸釋放內存,所以當你對1個引用指向的1大塊內存進行GC操作時,它會釋放所有內存,但是當有大量引用時,GC將以更小的內存釋放內存chuncks。

在第一個示例中,多次調用GC.start將釋放越來越多的內存。


這裏有2篇orther文章,深入挖掘:

相關問題