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