eryksun ha risposto alla domanda n. 1 e ho risposto alla domanda n. 3 (l'originale n. 4), ma ora rispondiamo alla domanda n. 2:
Perché in particolare rilascia 50.5mb - su quale importo viene rilasciato in base?
Ciò su cui si basa è, in definitiva, un'intera serie di coincidenze all'interno di Python e malloc
che sono molto difficili da prevedere.
Innanzitutto, a seconda di come stai misurando la memoria, potresti misurare solo le pagine effettivamente mappate nella memoria. In tal caso, ogni volta che una pagina viene sostituita dal cercapersone, la memoria verrà visualizzata come "liberata", anche se non è stata liberata.
Oppure potresti misurare pagine in uso, che possono o meno contare pagine allocate ma mai toccate (su sistemi che allocano in modo ottimistico, come Linux), pagine allocate ma taggate MADV_FREE
, ecc.
Se stai davvero misurando le pagine allocate (che in realtà non è una cosa molto utile da fare, ma sembra essere ciò di cui stai chiedendo), e le pagine sono state davvero dislocate, due circostanze in cui ciò può accadere: O tu ' brk
hai usato o equivalente per ridurre il segmento di dati (molto raro al giorno d'oggi), oppure hai usato munmap
o simile per rilasciare un segmento mappato. (In teoria esiste anche una variante minore di quest'ultima, in quanto vi sono modi per rilasciare parte di un segmento mappato, ad esempio rubandolo con MAP_FIXED
un MADV_FREE
segmento che si annulla immediatamente.)
Ma la maggior parte dei programmi non alloca direttamente le cose dalle pagine di memoria; usano un malloc
allocatore di stile. Quando chiami free
, l'allocatore può rilasciare pagine sul sistema operativo solo se ti capita di essere free
l'ultimo oggetto attivo in una mappatura (o nelle ultime N pagine del segmento di dati). Non è possibile che l'applicazione possa ragionevolmente prevederlo o persino rilevarlo in anticipo.
CPython lo rende ancora più complicato: ha un allocatore di oggetti a 2 livelli personalizzato sopra un allocatore di memoria personalizzato malloc
. (Vedi i commenti di origine per una spiegazione più dettagliata.) E per di più, anche a livello di API C, molto meno Python, non controlli nemmeno direttamente quando gli oggetti di livello superiore sono deallocati.
Quindi, quando rilasci un oggetto, come fai a sapere se rilascerà memoria sul sistema operativo? Bene, prima devi sapere che hai rilasciato l'ultimo riferimento (compresi eventuali riferimenti interni di cui non sapevi), consentendo al GC di deallocare. (A differenza di altre implementazioni, almeno CPython dislocerà un oggetto non appena è permesso.) Questo di solito disloca almeno due cose al livello successivo verso il basso (ad esempio, per una stringa, stai rilasciando l' PyString
oggetto e il buffer delle stringhe ).
Se si effettua la deallocazione di un oggetto, per sapere se ciò provoca il deallocazione di un blocco di archiviazione di oggetti al livello successivo, è necessario conoscere lo stato interno dell'allocatore di oggetti e come viene implementato. (Ovviamente non può succedere a meno che non si stia deallocando l'ultima cosa nel blocco e anche in questo caso, potrebbe non accadere.)
Se si fa rilasciare un blocco di stoccaggio oggetto, per sapere se questo provoca una free
chiamata, è necessario conoscere lo stato interno del allocatore PyMem, e come è implementato. (Ancora una volta, devi deallocare l'ultimo blocco in uso all'interno di una malloc
regione ed, e anche in questo caso, potrebbe non accadere.)
Se si esegue free
una malloc
regione ed, per sapere se ciò provoca un munmap
o equivalente (o brk
), è necessario conoscere lo stato interno del malloc
, nonché come è implementato. E questo, a differenza degli altri, è altamente specifico per la piattaforma. (E di nuovo, in genere è necessario deallocare l'ultimo in uso malloc
all'interno di un mmap
segmento e anche in questo caso, potrebbe non accadere.)
Quindi, se vuoi capire perché è successo a rilasciare esattamente 50.5mb, dovrai rintracciarlo dal basso verso l'alto. Perché non malloc
mappare 50.5 MB di pagine quando hai fatto quelle una o più free
chiamate (probabilmente per un po 'più di 50.5 MB)? Dovresti leggere la tua piattaforma malloc
, quindi camminare tra le varie tabelle ed elenchi per vedere il suo stato attuale. (Su alcune piattaforme, potrebbe persino fare uso di informazioni a livello di sistema, che è praticamente impossibile da catturare senza fare un'istantanea del sistema per ispezionare offline, ma per fortuna questo di solito non è un problema.) E poi devi fai la stessa cosa ai 3 livelli sopra.
Quindi, l'unica risposta utile alla domanda è "Perché".
A meno che tu non stia facendo uno sviluppo limitato di risorse (ad esempio, incorporato), non hai motivo di preoccuparti di questi dettagli.
E se stai sviluppando risorse limitate, conoscere questi dettagli è inutile; devi praticamente eseguire un end-run attorno a tutti quei livelli e in particolare mmap
alla memoria di cui hai bisogno a livello dell'applicazione (possibilmente con un allocatore di zona semplice, ben compreso e specifico per l'applicazione in mezzo).