问题是:在 2.2.1 中 fork 和调用 GC 时内存重复。这样做的主要问题是,在处理高达 3GB 的海量数据时,我的机器在一次分叉后就被杀死了。
我们编写了一个重现问题的小程序(见附件)。
该程序实例化一个对象,然后分叉成两个进程。GC 在子进程中被调用。内存分配(由 /proc/pid/smaps 给出)从共享变为私有,从而表明内存消耗翻了一番。
这是程序的输出(大小以 mb 为单位):
https://bugs.ruby-lang.org/issues/10559#change-50245
我们已经使用 ruby 1.9.3、2.1.3 和 2.2.1(最新)在 Ubuntu 14.04 上测试了该程序。测试是在新安装的 Ubuntu 机器上进行的,因此没有涉及其他软件。
我们还尝试 fork 10 个子节点,发现内存消耗翻了 10 倍,该问题仅在运行 GC 后出现。
问题:这个问题的根源是什么(Ruby、内核、Ubuntu)以及可以用它做什么?
该程序的源代码可以在这里找到:https ://bugs.ruby-lang.org/issues/10559#change-50245
编辑 :
这是我处理的代码。
def memory_object( size)
count = size/20
count.times do
result << "%20.18f" % rand
end
return result
end
big_memory = memory_object( 1000 * 1000* 30)
pid = fork do
big_memory_1 = memory_object( 1000 * 1000*30)
sleep( 1)
STDOUT.flush
exit!
end
Process.wait( pid)
如果您在 linux 上运行上述代码并使用 smaps 监控共享内存,您会看到在子进程中创建新对象的那一刻,整个内存都变得私有,但它不应该因为我什至没有修改原始对象。然而,有趣的是,如果像下面这样创建附加到数组的字符串,那么一切都会正常运行。
result << rand.to_s
我怀疑这是因为底层版本产生的垃圾更少。但即使我在 fork 之前多次强制 GC,它仍然会发生。我怀疑这是因为所有内容都分配在 GC 堆上,实际上已被修改,这导致了写时复制。有可能吗?