1

问题是:在 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 堆上,实际上已被修改,这导致了写时复制。有可能吗?

4

0 回答 0