2013-02-26 17 views
9

Mam zadanie uruchomione przy produkcji, która przetwarza pliki xml. pliki xml liczy około 4k i od wielkości 8 do 9 GB razem.Errno :: ENOMEM: Nie można przydzielić pamięci - cat

Po przetworzeniu otrzymujemy pliki CSV jako dane wyjściowe. Mam polecenia cat który połączy wszystkie pliki CSV do jednego pliku dostaję:

ERRNO :: ENOMEM: Nie można przydzielić pamięci

na komendę cat (lewy apostrof).

Poniżej przedstawiamy kilka szczegółów:

  • System Memory - 4 GB
  • Swap - 2 GB
  • Ruby: 1.9.3p286

Pliki są przetwarzane przy użyciu nokogiri i saxbuilder-0.0.8.

Tutaj znajduje się blok kodu, który przetworzy 4 000 plików XML, a dane wyjściowe zostaną zapisane w pliku CSV (1 na xml) (przepraszam, nie mam zamiaru udostępniać go b'coz zasad firmy).

Poniżej znajduje się kod, który będzie łączyć pliki wyjściowe do jednego pliku

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

Mam podjętej migawek zużycie pamięci podczas processing.It zużywa prawie wszystkie części pamięci, ale to nie będzie zawieść. Zawsze kończy się niepowodzeniem na komendzie cat.

Podejrzewam, że na backtick próbuje rozwidlić nowy proces, który nie ma wystarczająco dużo pamięci, więc nie powiedzie się.

Proszę dać mi znać swoją opinię i alternatywę dla tego.

+0

IMO byłoby sensownie pokazać, co robisz. –

+0

@DaveNewton Edytowałem swój wpis, dziękuję za odpowiedź – Atith

+0

Może być bardzo mało pamięci, aby tak się stało, czy na pewno masz wystarczająco dużo pamięci? Jaki jest wynik działania '' free -m''? – Intrepidd

Odpowiedz

2

Wygląda na to, że Twój system działa dość nisko na pamięć, a pojawienie się powłoki i wywołującego kota jest zbyt duże dla pozostałej pamięci.

Jeśli nie masz nic przeciwko straceniu prędkości, możesz scalić pliki w ruby, z małymi buforami. Pozwala to uniknąć tarowania powłoki i można kontrolować rozmiar bufora.

To niesprawdzone ale masz pomysł:

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 
+0

Tak, to może zadziałać, spróbuję tego i dam ci znać. Czy znasz jakieś problemy Nokogiri dotyczące Ruby 1.9.3 związane z pamięcią? Niedawno uaktualniliśmy ruby ​​z wersji 1.9.2 do 1.9.3, mam wrażenie, że to też może być powód. – Atith

2

Mam ten sam problem, ale zamiast cat to było sendmail (gem mail).

Znalazłem problem & rozwiązanie here instalując klejnot posix-spawn, np.

gem install posix-spawn 

a oto przykład: tworzenie proces dziecko

a = (1..500_000_000).to_a 

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

Ten czas powinien odnieść sukces.

Zobacz także: Minimizing Memory Usage for Creating Application Subprocesses w Oracle.

2

Prawdopodobnie nie masz fizycznej pamięci, więc sprawdź to i zweryfikuj swap (free -m). Jeśli nie masz miejsca do zamiany, create one.

W przeciwnym razie, jeśli pamięć jest w porządku, błąd jest najprawdopodobniej spowodowany ograniczeniami zasobów powłoki. Możesz je sprawdzić przez ulimit -a.

Można je zmienić za pomocą ulimit, które mogą modyfikować limity zasobów powłoki (patrz: help ulimit), np.

ulimit -Sn unlimited && ulimit -Sl unlimited 

aby te ograniczenia trwały, można go skonfigurować, tworząc plik ustawień ulimit za pomocą następującego polecenia powłoki:

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 

Albo użyć /etc/sysctl.conf aby zmienić limit globalnie (man sysctl.conf) np

kern.maxprocperuid=1000 
kern.maxproc=2000 
kern.maxfilesperproc=20000 
kern.maxfiles=50000 
Powiązane problemy