我试图理解从Ruby堆分配的内存何时返回到操作系统。我知道Ruby永远不会返回分配给它的堆的内存,但我仍然不确定堆内存的行为。即那些不符合40字节RVALUE的对象。
考虑以下程序,它分配一些大字符串然后强制主要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可以提供解释,但我会对其他人的解释感兴趣。
将内存释放回内核也需要付出代价。用户空间记忆 分配器可以保持该内存(私下),希望它可以 在同一个进程中重用,而不是将其返回给内核 用于其他过程。
答案 0 :(得分:1)
@joanbm在这里有一个非常好的观点。他引用了article explains this pretty well:
Ruby的GC逐渐释放内存,所以当你在1个引用所指向的1大块内存上执行GC时它会释放所有内容,但是当有大量引用时,GC会释放较小的chuncks中的内存。
对GC.start
的多次调用将在第一个示例中释放越来越多的内存。
以下是2篇深入挖掘的文章: