16

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

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

Errno::ENOMEM: 无法分配内存

on cat(反引号)命令。

以下是一些细节:

  • 系统内存 - 4 GB
  • 交换 - 2 GB
  • 红宝石:1.9.3p286

使用nokogiri和处理文件saxbuilder-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它总是在命令上失败。

我想,在反引号时,它会尝试分叉一个没有足够内存的新进程,所以它失败了。

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

4

3 回答 3

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
于 2013-02-26T14:35:24.457 回答
3

您的物理内存可能已用完,因此请仔细检查并验证您的交换 ( free -m)。如果您没有交换空间,请创建一个.

否则如果你的记忆力没问题,这个错误很可能是由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
于 2016-07-10T02:53:03.600 回答
2

cat我有同样的问题,但不是sendmailgem mail)。

我通过安装gem在这里找到了问题和解决方案,例如posix-spawn

gem install posix-spawn

这是一个例子:

a = (1..500_000_000).to_a

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

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

另请参阅:最小化在 Oracle 中创建应用程序子进程的内存使用。

于 2015-04-04T08:49:11.627 回答