web-dev-qa-db-ja.com

Errno :: ENOMEM:メモリを割り当てられません-猫

XMLファイルを処理するジョブを本番環境で実行しています。 xmlファイルは約4kで、サイズは8〜9 GBです。

処理後、CSVファイルを出力として取得します。すべてのCSVファイルを1つのファイルにマージするcatコマンドがあります。

Errno :: ENOMEM:メモリを割り当てられません

cat(バックティック)コマンド。

以下に詳細をいくつか示します。

  • システムメモリ-4 GB
  • スワップ-2 GB
  • Ruby: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コマンドでは常に失敗します。

おそらく、バックティックでは、十分なメモリを取得できない新しいプロセスをforkしようとするため、失敗します。

あなたの意見とこれに対する代替案を教えてください。

14
Atith

したがって、システムのメモリがかなり少なくなり、シェル+を呼び出すcatを生成するだけでは、残りのメモリが少なすぎます。

少し速度を落としてもかまわない場合は、小さなバッファーを使用してRubyでファイルをマージできます。これにより、シェルの生成が回避され、バッファーサイズを制御できます。

これはテストされていませんが、あなたはアイデアを得ます:

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
3
Intrepidd

物理メモリが不足している可能性があるため、再確認してスワップを確認してください(free -m)。スワップスペースがない場合は、 create one を使用します。

それ以外の場合、メモリに問題がない場合、エラーはシェルリソースの制限が原因である可能性が高いです。 ulimit -aで確認できます。

これらは、シェルのリソース制限を変更できるulimitによって変更できます(以下を参照してください:help ulimit)。

ulimit -Sn unlimited && ulimit -Sl unlimited

これらの制限を永続的にするには、次のシェルコマンドで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
3
kenorb

同じ問題がありますが、catの代わりにsendmailgem mail)。

私は問題と解決策を見つけました ここ をインストールすることによってposix-spawn gem、たとえば.

gem install posix-spawn

そしてここに例があります:

a = (1..500_000_000).to_a

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

今回は子プロセスの作成は成功するはずです。

関連項目: アプリケーションサブプロセスを作成するためのメモリ使用量の最小化 Oracle。

2
unixs