Topic: Pulizia memoria interprete python  (Letto 954 volte)

0 Utenti e 1 Visitatore stanno visualizzando questo topic.

Offline ytsejam

  • python habilis
  • **
  • Post: 99
  • Punti reputazione: 0
    • Mostra profilo
Pulizia memoria interprete python
« il: Gennaio 26, 2018, 15:48 »
Ciao, ho bisogno di un aiuto, sono sempre il solito rompiscatole, ma voglio innanzitutto dirvi grazie, da voi sto imparando molte cose.

In un progetto, quando faccio import, si carica in memoria la libreria chiamata ovviamente, ed occupa una sua fetta di ram.

Più librerie più fette di ram.

Come si può fare una pulizia ad un certo punto, per riportare la Shell come se fosse appena aperta senza riavviarla? con quale comando?
Ho letto del comando gc ma non pulisce nulla, la memoria impegnata resta identica quando lo provo. Grazie

Offline tommyb1992

  • python neanderthalensis
  • ****
  • Post: 299
  • Punti reputazione: 0
    • Mostra profilo
Re:Pulizia memoria interprete python
« Risposta #1 il: Gennaio 26, 2018, 16:29 »
Dubito abbia un minimo di senso ma...

import sys
del sys
print(sys.path)

Offline ytsejam

  • python habilis
  • **
  • Post: 99
  • Punti reputazione: 0
    • Mostra profilo
Re:Pulizia memoria interprete python
« Risposta #2 il: Gennaio 26, 2018, 18:10 »
Cosi non va  ;:(

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 2.876
  • Punti reputazione: 9
    • Mostra profilo
Re:Pulizia memoria interprete python
« Risposta #3 il: Gennaio 26, 2018, 21:16 »
Non riesco davvero a capire se stai mirando a trovare modi esotici per scassare il tuo computer... ma allora perché darsi tanta pena, davvero, basta un martello...

Comunque, non ti sembra ovvio? Se espandi la collezione di nomi accessibili a runtime, il tuo processo "python.exe" occuperà più memoria di conseguenza. Questo avviene allo stesso modo sia importando dei moduli, sia creando diecimila oggetti in un ciclo for, per dire.
"Liberare la memoria" non è una cosa che ti deve interessare, in python. Ci pensa il garbage collector. Se vuoi "liberare TUTTA la memoria", l'unica soluzione ovviamente è terminare python (e magari chiudere la shell).
Se proprio vuoi "liberare la memoria" occupata da un oggetto, allora puoi provare con del su un nome. Se quel nome è l'unico riferimento rimasto per l'oggetto, allora del impegna il garbage collector a liberare la memoria corrispondete in un momento imprecisato nel futuro. Ovviamente puoi usare del su qualsiasi nome, compreso quello che si riferisce a un modulo importato, se vuoi.
Ma il succo è... non importa mai niente a nessuno di usare del e "liberare memoria", tranne in casi particolarissimi. Semplicemente, python non si usa in questo modo.


Non sono sicuro, ma... potresti studiare python, credo. E' un bellissimo linguaggio di programmazione. Prova a seguire un libro passo-passo dalla prima pagina. Il Lutz è molto buono, e da queste parti lo si consiglia sempre.

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.453
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re:Pulizia memoria interprete python
« Risposta #4 il: Gennaio 27, 2018, 14:56 »
Dai Ric, qui hai mancato tu il problema (e Tommy, tu hai mancato la soluzione). Allora, posto che io non so se OP abbia davvero bisogno di questa cosa o sia uno sfizio. E non idea se questo sia un tentativo di soluzione ad un problema che si dovrebbe risolvere in altra maniera.

Ma il punto generale sollevato da OP e' completamente corretto. Ho *spesso* visto il problema "scaricare moduli". Specie quando le cose crescono (specialmente se hai un'architettura a plugin e worker generici) a furia di caricare librerie a runtime vai a cubare RAM. Anche perche' spesso e volentieri vuoi avere un certo numero di worker (che ti determina quante richieste puoi servire con una macchina per quanto di tempo). Questa e' una metrica importante quando devi fare scalare le cose (e capire quanto ti costa, o dimensionare parametri del loadbalancer, etc etc etc). Non e' il campo in cui mi muovo, ma suppongo che questa cosa possa essere pure molto rilevante se fai python su dispositivi a risorse limitate.

Ora, detto semplicemente, questo problema non ha una soluzione nota. Nel senso che si sa che non e' supportato in Python: https://bugs.python.org/issue9072
Sicuramente non in Python 2. Ci sono vaghe promesse per Python 3, ma in generale non mi risulta che siano concrete. Nota che questo problema lo ho visto in tutti i linguaggi relativamente dinamici (in pratica in C/C++ so come risolvere il problema, ma e' laborioso). In Java ci sono soluzioni praticabili (ma che io sappia solo Osgi offre qualcosa di simile off-the-shelf). Python (e Perl... quanto dolore... e sembra che anche Ruby) soffrono davvero molto di questo problema.

Non se ne esce. Se ci vuole questo livello di controllo della memoria, semplicemente bisogna guardare altrove. L'unica soluzione praticabile e' quella di ammazzare periodicamente i worker e cercare di fare in modo tale che non vengano caricate troppe librerie a sbalzo. Ma... si fa quello che si puo.

Diciamo che questo problema non ha soluzione e che l'unico modo di risolverlo e' "non trovarcisi" oppure lavorare a livello di architettura per risolverne una versione semplificata. Il problema generico e' intrattabile. Mi spiace per la risposta, ma e' semplicemente inutile insistere: non si puo' fare.

Possono venire in mente tante soluzioni apparenti che sembrano funzionare, ma in generale non se ne esce. Non e' banale nemmeno librerare memoria (al sistema operativo) rimuovendo oggetti normali. Questo e' legato a come sonzialmente sono fatte le librerie di allocazione della memoria (e.g., malloc) e a come funzionano i sistemi operativi. Quando si devono fare queste cose, il modo piu' semplice e' gestirsi le pagine di memoria a mano. Che vuole dire ancora una volta C/C++/Rust (forse) et similia, e in generale si ha un componente legato a doppio filo su un OS (per esempio ci si restringe ad essere posix -- cosa che alla fine ormai e' piuttosto cross, ma still --). E sono use case molto specifici, che prendono un monte di tempo per essere debuggati e fatti funzionare a modo. Non sono cose che si improvvisano e i programmatori "by coincidence" farebbero bene a non provarci nemmeno. Anche perche' in generale ci sono soluzioni piu' semplici.

Java, che da un punto di vista della piattaforma -- dovrei effettivamente parlare di JVM -- e' 10 anni avanti alle cose relativamente imbarazzanti che ci spacciano come VM a noialtri, ha qualche supporto per questo tipo di cosa. Ma Java/JVM ha un memory model formale e definito e ben progettato. E la gente lo ha sempre dovuto mettere in produzione in scenari piuttosto interessanti. E anche Java, in generale, tende a fare tutta questa cosa in modo riluttante: ritornare memoria al sistema operativo e' costoso e porta benefici estremamente limitati (visto che la memoria virtuale e' ormai una feature piuttosto comune). Ovviamente, embedded buona fortuna... ma forse li si vorrebbe comunque lavorare nei vari C, C++ e compagnia.

La gente che ha fatto la JVM ha anche capito una verita' fondamentale, che fintanto che sviluppavo "a casa" criticavo e non capivo: le applicazioni Java hanno memoria finita. Nel momento che i computer hanno memoria finita, non ha senso avere processi con memoria arbitraria. Preferisco avere limiti invalicabili e progettare in modo tale che un componente possa fallire. Applicazioni che crescono arbitrariamente richiedono di avere in giro OOM killer e simili e tipicamente si hanno quindi comunque fallimenti arbitrari (con la differenza che sono piu' brutali, da fuori, e nel frattempo si e' impattata la macchina, potenzialmente anche al punto da rendere difficile farci maintenance -- ci sono anche trick tipo preallocare memoria per una sessione SSH di emergenza... ma che due coglioni. piu' semplice dire tu hai 2 GB e fine della fiera).

In realta' il lavoro piu' interessante di questi tempi nel mondo della gestione della memoria sta succedendo nell'ecosistema Go... specialmente nel GC. Ma che io sappia anche li non si fa davvero unload dei moduli. E il claim e' che Go in generale faccia madvise al sistema operativo per dirgli di riprendersi memoria, ma in generale i sistemi operativi ignorano questa cosa e apparentemente parte comunque OOM killer -- suppongo che facendo tuning opportuno si riesca ad evitare, ma siamo davvero fuori dalla mia sfera di competenze: sono supposizioni --.

Offline tommyb1992

  • python neanderthalensis
  • ****
  • Post: 299
  • Punti reputazione: 0
    • Mostra profilo
Re:Pulizia memoria interprete python
« Risposta #5 il: Gennaio 27, 2018, 18:40 »
Beh indubbiamente sono tutte cose interessanti, sono sicuro che OP le terrà a mente fra un kill di svchost e un modulo importato con un def pre-generato... xD

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.453
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re:Pulizia memoria interprete python
« Risposta #6 il: Gennaio 27, 2018, 20:36 »
Beh indubbiamente sono tutte cose interessanti, sono sicuro che OP le terrà a mente fra un kill di svchost e un modulo importato con un def pre-generato... xD

Ma mica si scrive solo per OP. Ci sono tante altre persone che leggono. Detto questo, se capisce che generare uno script python e poi generarlo e' una cattiva idea, gia' e' un buon risultato.
Magari si rende conto che le funzioni (e le classi) possono avere *parametri* che si possono usare per cambiare il loro comportamento a runtime e che i programmi possono caricare *dati* per che possono cambiare il loro comportamento (e file di configurazione).

Non riesco davvero ad immaginarmi il caso in cui sia conveniente scrivere un programma che scrive un altro programma e poi lo esegue... se sa scriverlo, potrebbe benissimo eseguirlo direttamente. E se sono due processi diversi, ci sono modi migliori di farli parlare che scrivere un file da eseguire da qualche parte.

Nota che la questione e' la pregenerazione automatica: ci sono tantissimi motivi per avere un programma che esegue pezzi di codice separati. Per esempio e' un modo di definire il concetto di plugin. Ma cose piu' specifiche: un sistema di CI avra' degli stadi che fanno testing... e quindi che caricano programmi che vengono messi sul filesysyem con lo scopo di essere eseguiti (i test e il codice che stanno testando). Ok, facendo nitpicking estremo, se hai un sistema di CI come quello di cui sopra e stai testando qualche stub/binding autogenerato (che so... hai in giro un pezzo di CORBA e quindi avrai del codice che e' auto-generato a partire da una definizione IDL di cui magari vuoi eseguire i test. Ma qualcosa mi dice che questo non e' lo use case di OP (cioe', se lo e', dimentica soluzioni custom: jenkins-ci o quello che va di moda di questi giorni... comunque dare un occhio al buon jenkins non e' che faccia male).

Ma quando si parla di "generare automaticamente" un programma che qualcun'altro esegue, allora e' molto meglio mandargli una richiesta di eseguire qualcosa. Che so... una chiamata REST via HTTP(s), mica rocket science... e' roba piuttosto di base.

Ma scusa... dimentica Python, non ti verrebbe da dire che fai meno fatica a scrivere una pagina PHP che a seconda di come la chiami fa cose diverse?

Offline tommyb1992

  • python neanderthalensis
  • ****
  • Post: 299
  • Punti reputazione: 0
    • Mostra profilo
Re:Pulizia memoria interprete python
« Risposta #7 il: Gennaio 27, 2018, 21:21 »
Citazione
Ma mica si scrive solo per OP. Ci sono tante altre persone che leggono

Ma si ti pare... tu hai fatto benissimo a scrivere ciò che hai scritto.

E immagino che abbia anche un senso in certi casi.

Citazione
Ma scusa... dimentica Python, non ti verrebbe da dire che fai meno fatica a scrivere una pagina PHP che a seconda di come la chiami fa cose diverse?

Con php si fa meno fatica a prescindere :) Permette un approccio molto più tardo-friendly.

Però non ho mai visto fare roba come:
f=open("test.py")
f.write("[ code ]")
f.close()
[....]
import test

Ho visto salvare variabili nei vecchi forum/cms anni 2005-2007 quando andavano i flat-database per registrare utenti e posts. Ma non mi sembra di vederne di sopravvissuti (per fortuna).
« Ultima modifica: Gennaio 28, 2018, 07:55 da tommyb1992 »

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 2.876
  • Punti reputazione: 9
    • Mostra profilo
Re:Pulizia memoria interprete python
« Risposta #8 il: Gennaio 27, 2018, 21:22 »
Bello.
Non avevo idea del "baco" 9072, e in realtà non mi è mai venuto in mente di verificare se dopo un del modulo effettivamente la memoria si liberava... ma appunto, non è per cose del genere che usi python per cominciare.

> Ma mica si scrive solo per OP. Ci sono tante altre persone che leggono.
assolutamente +1. Io, per esempio. Un problema che mi sembrava banale adesso è rimasto... banale come prima, a lato pratico, ma intanto ho scoperto delle affascinanti complicazioni di cui magari non avrò mai bisogno ma chissà.

Per quanto riguarda l'altro problema dell'OP, mah... credo che semplicemente cercava di caricare dati in json senza sapere che si può fare con json.

Offline ytsejam

  • python habilis
  • **
  • Post: 99
  • Punti reputazione: 0
    • Mostra profilo
Re:Pulizia memoria interprete python
« Risposta #9 il: Gennaio 29, 2018, 12:26 »
Ringrazio tutti, spiego in poche parole il dilemma.
Uso python per lavoro, non direttamente con la sua shell ma su un software industriale, di cui ne fa parte, e come versione installata ha la 3.x

Questo software offre la possibilità di automatizzare tutti i calcoli e non solo.
Gli script utilizzati scritti sono centinaia, di oltre 600 righe caduno, per non parlare di uno principale, ormai diventata una libreria da cui vengono richiamati centinaia di def all'occorrenza, che ha un totale di oltre 16000 righe.
Per motivi di produzione molti script lavorano in autonomo, con cicli while True, perché sono notte e giorno sempre in funzione.
Il motivo principale è proprio questo, immaginate un pc server in cui gli arrivano 1000 informazioni al giorno e di queste informazioni deve elaborarle e renderle disponibili alla produzione, per fare questo i cicli infiniti ci devono essere per forza, ma il punto debole è proprio questo, la Ram viene impegnata sempre di più, perchè al primo ciclo completato restano memorizzati oggetti, liste, moduli importati ecc... che purtroppo non posso richiamare a monte una sola volta, proprio perchè spesso cambia il tipo di analisi da applicare e la RAM viene saturata presto ciclo dopo ciclo!
Mi rendo conto che sono su uno dei grandi forum di python, e ho a che fare con gente esperta che davvero sa cosa dice e scrive ed io sono solo un puntino insignificante e i vostri commenti sono perfettamente comprensibili, ma purtroppo ho questo problema e devo trovare una soluzione, perdonatemi se non sono un esperto come voi ma solo un principiante che prova a scrivere 4 righe e fare domande insensate, ma nel mio piccolo tanto insensate non sono fidatevi.

Grazie
« Ultima modifica: Gennaio 29, 2018, 12:28 da ytsejam »

Offline GlennHK

  • python sapiens sapiens
  • ******
  • Post: 1.655
  • Punti reputazione: 1
    • Mostra profilo
    • La Tana di GlennHK
Re:Pulizia memoria interprete python
« Risposta #10 il: Gennaio 29, 2018, 14:44 »
Ma una curiosità, giusto per capire, ci sono un po' di numeri alla mano?


Perché imho l'importazione di un modulo non ha chissà quale grande footprint in memoria, e poi le istanze dei moduli dovrebbero essere dei singleton.


Un minimo di profiling per capire cosa occupi così tanta memoria?


Per dire, io ho fatto una prova generando 20k di file python (vuoti) e importandoli tutti, e l'utilizzo di memoria è cresciuto di circa 40 mb. Ok che i file erano vuoti... ma 20k di import dovrebbero alzare un campanello d'allarme a monte.

Offline ytsejam

  • python habilis
  • **
  • Post: 99
  • Punti reputazione: 0
    • Mostra profilo
Re:Pulizia memoria interprete python
« Risposta #11 il: Gennaio 29, 2018, 15:18 »
Ma una curiosità, giusto per capire, ci sono un po' di numeri alla mano?


Perché imho l'importazione di un modulo non ha chissà quale grande footprint in memoria, e poi le istanze dei moduli dovrebbero essere dei singleton.


Un minimo di profiling per capire cosa occupi così tanta memoria?


Per dire, io ho fatto una prova generando 20k di file python (vuoti) e importandoli tutti, e l'utilizzo di memoria è cresciuto di circa 40 mb. Ok che i file erano vuoti... ma 20k di import dovrebbero alzare un campanello d'allarme a monte.

Ho fatto delle prove, un ciclo che printa 100 volte CIAO ed ogni volta che lo fa la RAM occupata aumenta, eppure in quel caso non viene importato nulla, ne creati oggetti ecc...
Ma è possibile questa cosa?

Offline RicPol

  • python sapiens sapiens
  • ******
  • Post: 2.876
  • Punti reputazione: 9
    • Mostra profilo
Re:Pulizia memoria interprete python
« Risposta #12 il: Gennaio 29, 2018, 18:08 »
Ora, quello che scrivi è troppo confuso per capirci qualcosa. Parli di "script che lavorano in autonomo", "con cicli while True" (le due cose potrebbero essere collegate, oppure no). Poi parli anche di "uno principale" che "richiama (richiama?????????? eh??????) centinaia di def (eh??????)", come se questo script principale facesse degli import degli altri script (ma magari mi sbaglio, non si capisce in effetti).

Ora... al di là di tutto, forse per prima cosa dovresti almeno rozzamente distinguere tra DATI e CODICE. Voglio dire, posso immaginarmi una situazione in cui ho 1000 MODULI PYTHON da importare, quando in effetti ho 1000 ALGORITMI DIVERSI da eseguire. Che poi, anche in questo caso, insomma... stiamo parlando di python... metaclassi, metaprogrammazione, metatutto a pranzo e a cena... boh, prima di tutto mi farei venire in mente se non c'è un modo per fattorizzarli, generarli al volo, questi mille algoritmi. Ma comunque.

Ripeto, non si capisce esattamente qual è la tua situazione e il tuo problema. Magari in effetti è una situazione in cui qualcuno che non è mai andato oltre il primo capitolo del manuale si è messo a martellare un po' di script python qualche anno addietro, e poi la cosa è cresciuta in modo disordinato fino a una giungla di cui nessuno capisce niente. Succede, figurati. Però, se vuoi riparare tutto questo, forse ti conviene, almeno tu, andare oltre il primo capitolo del manuale...

Per prima cosa capisci se effettivamente questi mille moduli python, essenzialmente, sono lì perché fanno davvero mille COSE diverse, oppure sono lì solo perché ciascuno contiene un set di DATI diversi da elaborare. Cioè, se la tua situazione fosse (semplificando) qualcosa del genere...

# modulo_uno.py
DATA = [un lungo set di dati qualsiasi....]

def elabora(data=DATA):
     # una funzione che elabora i dati

#----------------------------------
# modulo_due.py
DATA = [un altro, diverso, lungo set di dati qualsiasi....]

def elabora(data=DATA):
     # la stessa medesima funzione che elabora i dati

# -----------------------------------
# ... e così via fino a modulo_mille.py

# -----------------------------------
# modulo_principale.py
import modulo_uno
import modulo_due
...
import modulo_mille
# o magari anche importando dinamicamente, come avevi chiesto in un altro thread se ben ricordo

modulo_uno.elabora()
modulo_due.elabora()
...
modulo_mille.elabora()
# o magari in modo più elegante, usando un ciclo, va a sapere.

... ecco, se la tua situazione fosse qualcosa del genere, allora questa sarebbe una sciocchezza.

Offline tommyb1992

  • python neanderthalensis
  • ****
  • Post: 299
  • Punti reputazione: 0
    • Mostra profilo
Re:Pulizia memoria interprete python
« Risposta #13 il: Gennaio 29, 2018, 18:18 »
Ma si può sapere che software è? Io sarei curioso di vedere l'architettura...

Offline ytsejam

  • python habilis
  • **
  • Post: 99
  • Punti reputazione: 0
    • Mostra profilo
Re:Pulizia memoria interprete python
« Risposta #14 il: Gennaio 30, 2018, 09:15 »
Ora, quello che scrivi è troppo confuso per capirci qualcosa. Parli di "script che lavorano in autonomo", "con cicli while True" (le due cose potrebbero essere collegate, oppure no). Poi parli anche di "uno principale" che "richiama (richiama?????????? eh??????) centinaia di def (eh??????)", come se questo script principale facesse degli import degli altri script (ma magari mi sbaglio, non si capisce in effetti).

Ora... al di là di tutto, forse per prima cosa dovresti almeno rozzamente distinguere tra DATI e CODICE. Voglio dire, posso immaginarmi una situazione in cui ho 1000 MODULI PYTHON da importare, quando in effetti ho 1000 ALGORITMI DIVERSI da eseguire. Che poi, anche in questo caso, insomma... stiamo parlando di python... metaclassi, metaprogrammazione, metatutto a pranzo e a cena... boh, prima di tutto mi farei venire in mente se non c'è un modo per fattorizzarli, generarli al volo, questi mille algoritmi. Ma comunque.

Ripeto, non si capisce esattamente qual è la tua situazione e il tuo problema. Magari in effetti è una situazione in cui qualcuno che non è mai andato oltre il primo capitolo del manuale si è messo a martellare un po' di script python qualche anno addietro, e poi la cosa è cresciuta in modo disordinato fino a una giungla di cui nessuno capisce niente. Succede, figurati. Però, se vuoi riparare tutto questo, forse ti conviene, almeno tu, andare oltre il primo capitolo del manuale...

Per prima cosa capisci se effettivamente questi mille moduli python, essenzialmente, sono lì perché fanno davvero mille COSE diverse, oppure sono lì solo perché ciascuno contiene un set di DATI diversi da elaborare. Cioè, se la tua situazione fosse (semplificando) qualcosa del genere...

# modulo_uno.py
DATA = [un lungo set di dati qualsiasi....]

def elabora(data=DATA):
     # una funzione che elabora i dati

#----------------------------------
# modulo_due.py
DATA = [un altro, diverso, lungo set di dati qualsiasi....]

def elabora(data=DATA):
     # la stessa medesima funzione che elabora i dati

# -----------------------------------
# ... e così via fino a modulo_mille.py

# -----------------------------------
# modulo_principale.py
import modulo_uno
import modulo_due
...
import modulo_mille
# o magari anche importando dinamicamente, come avevi chiesto in un altro thread se ben ricordo

modulo_uno.elabora()
modulo_due.elabora()
...
modulo_mille.elabora()
# o magari in modo più elegante, usando un ciclo, va a sapere.

... ecco, se la tua situazione fosse qualcosa del genere, allora questa sarebbe una sciocchezza.
La mia situazione è come il rigo 28.
In ogni caso non posso permettermi stravolgere il tutto, non sono a casa con un raspberry o altro che posso permettermi di fare prove, spegnere il pc e rinviare a quando mi va, bloccherei una produzione ed in ogni caso con le curiosità di tutti stiamo andando ben oltre il problema alla mia domanda.
Ho bisogno di pulire memoria ram mentre lavora questo programma, a fine di tutto, prima che ricomincia il ciclo da capo, Non esistono soluzioni?
Il garbage collect ad esempio, se usato per bene può essermi di aiuto?