Errno:: ENOMEM: не удается выделить память-cat


У меня есть работа, запущенная на производстве, которая обрабатывает xml-файлы. xml-файлы насчитывают около 4k и имеют размер от 8 до 9 Гб все вместе.

После обработки мы получаем CSV-файлы в качестве выходных данных. У меня есть команда cat, которая объединит все CSV-файлы в один файл, который я получаю:

Errno:: ENOMEM: не удается выделить память

По команде cat (Backtick).

Ниже приведены некоторые детали:

  • системная память-4 ГБ
  • Swap-2 ГБ
  • Рубин : 1.9.3p286

Файлы обрабатываются с помощью nokogiri и saxbuilder-0.0.8.

Здесь есть блок кода, который будет обрабатывать 4000 XML-файлов и вывод сохранен в CSV (1 на xml) (извините, я не предполагаю делиться им b'coz политики компании).

Ниже приведен код, который объединит выходные файлы в один файл

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

Я сделал снимки потребления памяти во время processing.It потребляет почти всю часть памяти, но, это не подведет. Он всегда терпит неудачу на cat команда.

Я думаю, на backtick он пытается развилить новый процесс, который не получает достаточно памяти, поэтому он терпит неудачу.

Пожалуйста, дайте мне знать Ваше мнение и альтернативу этому.
3 11

3 ответа:

Таким образом, кажется, что ваша система работает довольно мало памяти и порождение оболочки + вызов 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

Вероятно, у вас закончилась физическая память, поэтому дважды проверьте это и проверьте свою подкачку (free -m). Если у вас нет пространства подкачки, создайте его.

В противном случае, если ваша память в порядке, ошибка, скорее всего, вызвана ограничениями ресурсов оболочки. Вы можете проверить их с помощью 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

У меня та же проблема, но вместо cat она была sendmail (gem mail).

Я нашел проблему и решение здесь , установив posix-spawn gem, например

gem install posix-spawn

А вот пример:

a = (1..500_000_000).to_a

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

На этот раз создание дочернего процесса должно завершиться успешно.

Смотрите также: минимизация использования памяти для создания прикладных подпроцессов в Oracle.