ruby - Errno::ENOMEM:无法分配内存 - cat

标签 ruby shell out-of-memory fork spawn

我有一个在生产环境中运行的工作,它处理 xml 文件。 xml 文件总计约 4k,大小为 8 到 9 GB。

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

Errno::ENOMEM: Cannot allocate memory

cat(反引号)命令。

以下是一些细节:

  • 系统内存 - 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 命令上失败。

我想,在反引号上,它会尝试 fork 一个没有获得足够内存的新进程,因此它会失败。

请告诉我您的意见和替代方案。

最佳答案

因此看起来您的系统内存运行非常低,生成 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

关于ruby - Errno::ENOMEM:无法分配内存 - cat,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15086133/

相关文章:

shell - 在 Perl 中打开管道是否涉及 shell?

Java OutOfMemoryError 奇怪的行为

Android:奇怪的内存不足异常

ruby-on-rails - Rails Controller 中的功能测试重定向

ruby - nodeJs 中的 Redis-pubsub,执行 "HGET"命令

Ruby:获取方法的类或模块名称

c - 实现自己的 shell

ruby-on-rails - 如何在RestClient获取请求头中传递参数并访问 Controller 中的参数

linux - BASH getopt inside bash 函数

java - 如何从java中的文本文件中跳过特定行?