2013-02-26 14 views
9

Ho un lavoro in esecuzione sulla produzione che elabora i file xml. I file xml hanno un valore di circa 4k e di dimensione compresa tra 8 e 9 GB.Errno :: ENOMEM: Impossibile allocare memoria - cat

Dopo l'elaborazione otteniamo i file CSV come output. Ho un comando cat che unire tutti i file CSV in un singolo file sto ottenendo:

Errno :: ENOMEM: Impossibile allocare memoria

a comando cat (backtick).

Qui di seguito sono alcuni dettagli:

  • memoria di sistema - 4 GB
  • Swap - 2 GB
  • Rubino: 1.9.3p286

file vengono elaborati utilizzando nokogiri e saxbuilder-0.0.8.

Qui c'è un blocco di codice che elabora 4.000 file XML e l'output è salvato in CSV (1 per xml) (scusate, non credo di condividerlo con la politica aziendale).

Di seguito è il codice che unire i file di output in un unico file

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

ho preso istantanee di consumo di memoria durante processing.It consuma quasi tutti parte della memoria, ma, non lo farà fallire. Comincia sempre con il comando cat.

Suppongo che, con il backtick, provi a eseguire il fork di un nuovo processo che non ha memoria sufficiente, in modo da non riuscire.

Per favore fatemi sapere la vostra opinione e alternativa a questo.

+0

IMO che sarebbe senso di mostrare in realtà quello che stai facendo. –

+0

@DaveNewton Ho modificato il mio post, grazie per la tua risposta – Atith

+0

Potresti avere una memoria insufficiente perché ciò accada, sei sicuro di avere abbastanza memoria? Qual è l'output di '' free -m''? – Intrepidd

risposta

2

Quindi sembra che il tuo sistema stia funzionando abbastanza in basso sulla memoria e genera una shell + chiamare cat è troppo per la poca memoria rimasta.

Se non ti dispiace perdere un po 'di velocità, puoi unire i file in ruby, con buffer piccoli. In questo modo si evita di generare una shell e si può controllare la dimensione del buffer.

Questo non è testato, ma si ottiene l'idea:

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

Sì, questo potrebbe funzionare, ci proverò e ti faccio sapere. E conosci qualche problema di Nokogiri su Ruby 1.9.3 relativo alla memoria ?. Recentemente abbiamo aggiornato Ruby da 1.9.2 a 1.9.3, ho la sensazione che anche questa potrebbe essere una ragione. – Atith

2

Ho lo stesso problema, ma invece di cat era sendmail (gem mail).

Ho trovato il problema & soluzione here installando posix-spawn gem, ad es.

gem install posix-spawn 

e qui è l'esempio:

a = (1..500_000_000).to_a 

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

Questa volta la creazione di processo bambino dovrebbe avere successo.

Vedere anche: Minimizing Memory Usage for Creating Application Subprocesses su Oracle.

2

si sono probabilmente di memoria fisica, in modo da verificare che il doppio e verificare lo swap (free -m). Nel caso in cui non si disponga di uno spazio di scambio, create one.

In caso contrario, se la memoria è soddisfacente, è probabile che l'errore sia causato dai limiti delle risorse della shell. È possibile controllarli per ulimit -a.

Possono essere modificati ulimit che possono modificare i limiti delle risorse di shell (vedi: help ulimit), ad esempio

ulimit -Sn unlimited && ulimit -Sl unlimited 

per rendere questi limite persistente, è possibile configurarlo con la creazione del file di impostazione ulimit dal seguente comando shell:

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 

Oppure utilizzare /etc/sysctl.conf per modificare il limite globale (man sysctl.conf) , per esempio

kern.maxprocperuid=1000 
kern.maxproc=2000 
kern.maxfilesperproc=20000 
kern.maxfiles=50000 
Problemi correlati