Errno :: ENOMEM:无法分配内存 - 猫

时间:2013-02-26 10:01:15

标签: ruby shell out-of-memory fork spawn

我有一个正在运行的作业,它处理xml文件。 xml文件大约为4k,大小为8到9 GB。

处理完毕后,我们将CSV文件作为输出。我有一个cat命令,它将所有CSV文件合并到我正在获得的单个文件中:

  

Errno :: ENOMEM:无法分配内存

on cat(Backtick)命令。

以下是一些细节:

  • 系统内存 - 4 GB
  • 交换 - 2 GB
  • Ruby:1.9.3p286

使用nokogirisaxbuilder-0.0.8处理文件。

这里有一个代码块,它将处理4,000个XML文件,输出以CSV格式保存(每个xml 1个)(对不起,我不想在公司政策中分享它)。

下面是将输出文件合并为单个文件的代码

Dir["#{processing_directory}/*.csv"].sort_by {|file| [file.count("/"), file]}.each {|file|
            `cat #{file} >> #{final_output_file}`
}

我在处理过程中拍摄了内存消耗快照。它几乎占用了内存的所有部分,但是它不会失败。 它总是在cat命令上失败。

我想,在反击时,它会尝试派生一个新进程,但是没有足够的内存,所以它失败了。

请让我知道您的意见和替代方案。

3 个答案:

答案 0 :(得分:3)

所以看起来你的系统内存运行相当低,并且产生一个shell +调用cat对于剩下的几个内存来说太多了。

如果您不介意失去一些速度,可以使用小缓冲区合并ruby中的文件。 这样可以避免产生shell,并且可以控制缓冲区大小。

这是未经测试但您明白了:

buffer_size = 4096
output_file = File.open(final_output_file, 'w')

Dir["#{processing_directory}/*.csv"].sort_by {|file| [file.count("/"), file]}.each do |file|
  f = File.open(file)
  while buffer = f.read(buffer_size)
    output_file.write(buffer)
  end
  f.close
end

答案 1 :(得分:3)

您可能没有物理内存,因此请仔细检查并验证您的交换(free -m)。如果您没有交换空间,create one

否则,如果您的内存正常,则错误很可能是由shell资源限制引起的。您可以ulimit -a检查它们。

可以通过ulimit更改它们,这可以修改shell资源限制(请参阅:help ulimit),例如

ulimit -Sn unlimited && ulimit -Sl unlimited

要使这些限制持久化,可以通过以下shell命令创建ulimit设置文件来配置它:

cat | sudo tee /etc/security/limits.d/01-${USER}.conf <<EOF
${USER} soft core unlimited
${USER} soft fsize unlimited
${USER} soft nofile 4096
${USER} soft nproc 30654
EOF

或使用/etc/sysctl.conf全局更改限制(man sysctl.conf),例如

kern.maxprocperuid=1000
kern.maxproc=2000
kern.maxfilesperproc=20000
kern.maxfiles=50000

答案 2 :(得分:2)

我遇到了同样的问题,但cat代替sendmail gem mail

我发现问题&amp;解决方案here安装posix-spawn gem,例如

gem install posix-spawn

以下是示例:

a = (1..500_000_000).to_a

require 'posix/spawn'
POSIX::Spawn::spawn('ls')
  

这次创建子进程应该会成功。

另见:Oracle的Minimizing Memory Usage for Creating Application Subprocesses