Newsgroup: it.comp.lang.perl
Titolo: RAM utilizzata da Perl

Ciao a tutti.
Sto impazzendo da qualche giorno su un problema.
Ho scritto alcuni tool in Perl che prendono in input indirizzi IP da
files o da Database e fanno delle operazioni sugli apparati che hanno
quegli indirizzi.
Per farli ho utilizzato i moduli NET::Ping, NET::Telnet e NET::Ftp.
Oltre che il modulo threads.
Il problema è che questi script utilizzano una quantità abnorme di
RAM.
Quasi sicuramente il problema è nel mio codice... e vorrei per questo
chiedere se qualcuno sa darmi indicazioni su tutorial o qualunque tipo
di source dove reperire informazioni su come Perl gestisca variabili,
memoria eccetera.
Grazie!

[...]
Sono sempre io.
Mi voglio spiegare meglio e voglio fare un esempio, per aiutarvi ad
aiutarmi.
Il mio programma è fatto in questa maniera (schematizzato):
++++++++++++++++++++++++++++++++++++++++++++
require 
funzioni.pl
;  #mia raccolta di funzioni
while(1) {
  my @lista = <listadiindirizziip>;
  while (finisce la lista) {
    if (ping(indirizzo) {    #dove "ping" è una sub presente in 
funzioni.pl
        fai una serie di cose tra cui ftp e telnet;
    }
  }
}
aggiorna il file <listadiindirizziip>, se vuoto esci;
++++++++++++++++++++++++++++++++++++++++++++
Potrebbe essere il ricorrere al file esterno a causare il problema di RAM?
Oppure la variabile @lista non si svuota ad ogni ciclo?


La variabile @lista "si svuota" (per così dire) ad ogni ciclo, ma la RAM 
non viene restituita al sistema operativo: questo dipende dal SO e non 
da Perl (in ogni caso la RAM viene riutilizzata internamente da Perl 
durante l'esecuzione del programma).
Quello che succede è che metti *l'intero* contenuto del file nell'array 
@lista, perché stai utilizzando l'operatore <> in list context, per cui 
in pratica nel corso dell'esecuzione del programma, la RAM allocata sarà 
(almeno) pari alla dimensione del file listadiindirizziip.
Soluzione:
Leggi una riga alla volta dal file listadiindirizziip, e non l'intero 
file in un colpo solo, utilizzando l'operatore <> in scalar context 
anziché in list context:
while ( my $ip = <listadiindirizziip> ) {
	# Fai qualcosa con il singolo indirizzo,
	# contenuto in $ip.
}
Ciao,
Emanuele.

 anziché in list context:
Ottimizzerò nel modo che dici tu. Ma in ogni caso non si tratta mai di file
di dimensioni grandi. Non arrivano al mega.
Devo continuare ad indagare, userò i metodi "size" e "total_size" per
monitorare la dimensione di ogni singola variabile del programma... vediamo
un po' che cosa ne esce.
Grazie.

 di dimensioni grandi. Non arrivano al mega.
L'ho fatta (molto) più semplice di come è in realtà.
Anzitutto Perl ha un overhead di occupazione di memoria per ogni 
scalare. Poi ha un ulteriore overhead se lo scalare è una stringa, e poi 
ancora un altro overhead per gli array (per inciso, per gli hash 
l'overhead è ancora maggiore).
In definitiva la dimensione di un array di stringhe contenenti ognuna 
una riga del file non è uguale alla dimensione del file, ma maggiore.
Poi la gestione della memoria è molto più complicata, se si scende nei 
dettagli.
In taluni casi Perl può decidere di non deallocare (neanche 
internamente) le variabili lessicali, anche quando sono uscite dal loro 
scope e anche quando il loro reference count è uguale a zero, per 
ragioni velocistiche.
Infine anche se Perl dispone di memoria libera nel proprio memory pool, 
se ha bisogno di un blocco di memoria maggiore, richiede al SO quel 
blocco per intero, e non soltanto la porzione mancante al memory pool.
Per forzare incondizionatamente la deallocazione della memoria allocata 
ad una variabile puoi usare undef (in questo caso la memoria potrebbe 
anche essere restituita al SO, ma solo se il blocco supera una certa 
dimensione minima, tanto per fare le cose ancora più complicate...)
Prova quindi ad aggiungere la riga:
	undef @lista;
come ultima istruzione del ciclo in cui dichiari @lista (e poi facci 
sapere come va a a finire ;-)
Ciao,
Emanuele.

 scalare. Poi ha un ulteriore overhead se lo scalare è una stringa, e poi
[...]
Informazioni preziosissime!!!
Grazie!
Senti, per curiosità, io non sono riuscito, parlo di Internet, a trovare
questo tipo di info.
Puoi indirizzarmi o sono frutto di documentazione cartacea?

 Puoi indirizzarmi o sono frutto di documentazione cartacea?
Sono informazioni che provengono principalmente da Internet ma anche da 
documentazione cartacea (ed anche da mie sperimentazioni).
Le fonti sono talmente disparate che rintracciarle tutte è veramente uno 
sforzo sovrumano, credimi :-(
Comunque ci provo.
Qui ad esempio parla della mancata deallocazione delle variabili 
all'uscita dallo scope per ragioni di performance, oltre ad altre 
interessantissime informazioni sulla gestione della memoria in Perl
(questa è anche una fonte "cartacea", trattandosi di un libro)
http://modperlbook.org/html/ch14_02.html
Poi:
http://www.perlmonks.org/index.pl?node_id=108482
http://www.perlmonks.org/index.pl?node_id=104920
Overhead occupazione della memoria delle strutture dati Perl:
http://search.cpan.org/~dsugal/Devel-Size-0.63/Size.pm
#UNDERSTANDING_MEMORY_ALLOCATION
http://perldoc.perl.org/perldebguts.html#Debugging-Perl-memory-usage
Rilascio della memoria al SO, se, quando, come e perché:
http://www.perlmonks.org/?node_id=445661
http://www.perlmonks.org/?node_id=312203
http://www.perlmonks.org/?node_id=312249
Poi segui tutti i link presenti qui:
http://www.perlmonks.org/?node_id=336883
Ovviamente c'è molto altro: usa Google e, soprattutto, PerlMonks.
Beh, adesso però non lasciarmi con la curiosità e facci sapere se è 
cambiato qualcosa con undef @lista (il suggerimento originario circa la 
lettura da file riga per riga rimane la soluzione preferibile beninteso, 
anche perché undef incide molto sulle prestazioni).
Ciao,
Emanuele.

Domani, non appena ci avrò potuto mettere le mani, farò entrambe le
modifiche: file letto riga per riga e undef.
Poi cercherò di fare un po' di debug sulla dimensione delle variabili.
E scriverò di nuovo in questo tread per aggiornarvi sui risultati.
Grazie ancora.
"Emanuele Zeppieri" <ema...@REtiscaliMOVE.it> ha scritto nel messaggio
news:B9kgf.70443$Pe2.1...@twister2.libero.it...


 anche perché undef incide molto sulle prestazioni).
Come promesso, vi faccio sapere com'è andata.
Il metodo di lettura dei file l'ho cambiato con quello suggerito da voi e
qualcosina ho risolto.
Ho scoperto però che il grosso del problema era un altro: un utilizzo
probabilmente sbagliato dei thread.
Quello dei thread è un argomento che ho trovato un po' spinoso, nel senso
che ancora molte cose non mi sono chiare. Quello volevo fare era tenere
sotto controllo quanti thread giravano contemporaneamente per non lanciarne
troppi tutti insieme. Ora ci sono riuscito con un workaround che pero' non è
probabilmente la soluzione piu' efficiente ed elegante. In ogni caso, per
dare un po' di numeri, un programma che lancia un ping verso circa 2500
apparati, letti da file con il metodo riga per riga, con un controllo sui
thread che limita a 20 il numero massimo di ping contemporanei, succhia
praticamente tutto il processore e 50 Mb di RAM mentre è in esecuzione.
Vi sembrano cifre normali?