小编Tho*_*mus的帖子

Ruby 2.2中的垃圾收集器引发了意想不到的CoW

当我分叉我的进程时,如何防止GC激发写时复制?我最近一直在分析垃圾收集器在Ruby中的行为,因为我在程序中遇到了一些内存问题(即使对于相当小的任务,我的60核0.5Tb机器上的内存耗尽).对我来说,这确实限制了ruby在多核服务器上运行程序的实用性.我想在这里介绍我的实验和结果.

垃圾收集器在分叉期间运行时会出现问题.我调查了三个案例来说明这个问题.

情况1:我们使用数组在内存中分配了大量对象(字符串不超过20个字节).使用随机数和字符串格式创建字符串.当进程分叉并强制GC在子进程中运行时,所有共享内存都是私有的,导致初始内存重复.

情况2:我们使用数组在内存中分配了很多对象(字符串),但是使用rand.to_s函数创建了字符串,因此我们删除了与前一种情况相比的数据格式.我们最终使用的内存较少,可能是因为垃圾较少.当进程分叉并强制GC在子进程中运行时,只有部分内存变为私有.我们有重复的初始内存,但程度较小.

情况3:与之前相比,我们分配的对象更少,但对象更大,因此分配的内存量与之前的情况相同.当进程分叉并且我们强制GC在子进程中运行时,所有内存保持共享,即没有内存重复.

在这里,我粘贴用于这些实验的Ruby代码.要在不同情况之间切换,只需更改memory_object函数中的"option"值即可.在Ubuntu 14.04计算机上使用Ruby 2.2.2,2.2.1,2.1.3,2.1.5和1.9.3测试了代码.

案例1的示例输出:

ruby version 2.2.2 
 proces   pid log                   priv_dirty   shared_dirty 
 Parent  3897 post alloc                   38            0 
 Parent  3897 4 fork                        0           37 
 Child   3937 4 initial                     0           37 
 Child   3937 8 empty GC                   35            5 
Run Code Online (Sandbox Code Playgroud)

完全相同的代码是用Python编写的,在所有情况下,CoW都可以正常工作.

案例1的示例输出:

python version 2.7.6 (default, Mar 22 2014, 22:59:56) 
[GCC 4.8.2] 
 proces   pid log                   priv_dirty shared_dirty 
 Parent  4308 post alloc                35             0 
 Parent  4308 4 fork                     0            35 
 Child   4309 4 initial                  0            35 
 Child   4309 10 …
Run Code Online (Sandbox Code Playgroud)

ruby garbage-collection fork copy-on-write shared-memory

10
推荐指数
1
解决办法
620
查看次数