eryksun ha risposto alla domanda # 1, e io ho risposto alla domanda # 3 (l'originale # 4), ma ora cerchiamo di rispondere alla domanda # 2:
Perché si rilasciare 50.5mb in particolare - qual è l'importo che viene rilasciato in base a?
Quello su cui si basa è, in definitiva, tutta una serie di coincidenze all'interno di Python e malloc
che sono molto difficili da prevedere.
Innanzitutto, a seconda di come si sta misurando la memoria, è possibile misurare solo le pagine effettivamente mappate in memoria.In tal caso, ogni volta che una pagina viene scambiata dal cercapersone, la memoria viene visualizzata come "liberata", anche se non è stata liberata.
Oppure si possono misurare pagine in uso, che possono o non possono contare pagine assegnate ma non toccate mai (su sistemi che ottimizzano eccessivamente l'allocazione, come linux), pagine allocate ma contrassegnate MADV_FREE
, ecc.
Se si stanno veramente misurando le pagine allocate (che in realtà non è una cosa molto utile da fare, ma sembra essere quello che si sta chiedendo) e le pagine sono state effettivamente deallocate, due circostanze in cui ciò può Accade: O hai utilizzato brk
o equivalente per ridurre il segmento di dati (molto raro oggigiorno), oppure hai utilizzato munmap
o simile per rilasciare un segmento mappato. (C'è anche teoricamente una variante minore a questi ultimi, in quanto ci sono modi per liberare parte di un segmento-es mappato, rubare con MAP_FIXED
per un MADV_FREE
segmento che immediatamente unmap.)
Ma la maggior parte dei programmi non lo fanno allocare direttamente le cose dalle pagine di memoria; usano un allocatore stile malloc
. Quando chiami free
, l'allocatore può solo rilasciare pagine sul sistema operativo se ti capita di essere free
l'ultimo oggetto live in una mappatura (o nelle ultime N pagine del segmento dati). Non c'è modo in cui la tua applicazione può ragionevolmente prevedere questo, o addirittura scoprire che è successo in anticipo.
CPython rende tutto ciò ancora più complicato: ha un allocatore di oggetti personalizzato a 2 livelli sopra un allocatore di memoria personalizzato sopra a malloc
. (Vedi the source comments per una spiegazione più dettagliata). Inoltre, anche a livello di API C, molto meno Python, non si controlla nemmeno direttamente quando gli oggetti di livello superiore vengono deallocati.
Quindi, quando si rilascia un oggetto, come si fa a sapere se sta per rilasciare memoria sul sistema operativo? Bene, per prima cosa devi sapere che hai rilasciato l'ultimo riferimento (inclusi eventuali riferimenti interni che non conoscevi), consentendo al GC di deallocarlo. (A differenza di altre implementazioni, almeno CPython assegnerà un oggetto non appena è consentito.) Questo di solito rilascia almeno due cose al livello successivo (ad esempio, per una stringa, stai rilasciando l'oggetto PyString
e la stringa buffer).
Se fai deallocare un oggetto, per sapere se questo fa sì che il livello successivo verso il basso per rilasciare un blocco di stoccaggio oggetto, è necessario conoscere lo stato interno del allocatore oggetto, e come è implementato. (E, ovviamente, non può accadere se non si sta deallocando l'ultima cosa che nel blocco, e anche allora, non può accadere.)
Se fai rilasciare un blocco di stoccaggio oggetto, per sapere se questo cause una chiamata free
, è necessario conoscere lo stato interno dell'allocazione PyMem e il modo in cui è implementato. (Anche in questo caso, devi essere deallocando l'ultimo blocco in uso all'interno di una regione malloc
ndr, e anche allora, non può accadere.)
Se faifree
una regione malloc
Ed, per sapere se questo cause un munmap
o equivalente (o brk
), è necessario conoscere lo stato interno di malloc
e il modo in cui è implementato. E questo, a differenza degli altri, è altamente specifico per piattaforma. (E ancora, di solito devi deallocare l'ultimo in uso malloc
all'interno di un segmento mmap
, e anche allora, potrebbe non succedere.)
Quindi, se vuoi capire perché è successo a rilasciare esattamente 50.5 mb , dovrai rintracciarlo dal basso verso l'alto.Perché lo malloc
ha cancellato 50,5 MB di pagine quando hai effettuato quelle o più chiamate free
(probabilmente un po 'più di 50.5mb)? Dovresti leggere il numero malloc
della tua piattaforma, quindi percorrere le varie tabelle ed elenchi per vedere il suo stato corrente. (Su alcune piattaforme, potrebbe persino fare uso di informazioni a livello di sistema, il che è praticamente impossibile da catturare senza creare un'istantanea del sistema per l'ispezione offline, ma fortunatamente questo non è di solito un problema.) E poi devi fai la stessa cosa ai 3 livelli sopra.
Quindi, l'unica risposta utile alla domanda è "Perché".
A meno che non si stia realizzando uno sviluppo a risorse limitate (ad esempio, incorporato), non si ha motivo di preoccuparsi di questi dettagli.
E se si è fare sviluppo limitato alle risorse, conoscere questi dettagli è inutile; devi praticamente eseguire un end-run su tutti questi livelli e in particolare su mmap
la memoria di cui hai bisogno a livello di applicazione (possibilmente con un semplice, ben compreso, allocatore di zona specifico dell'applicazione in mezzo).
Vale la pena notare che questo comportamento non è specifico per Python. In genere, quando un processo libera una memoria allocata nell'heap, la memoria non viene rilasciata sul sistema operativo fino alla sua morte. – NPE
La tua domanda richiede più cose, alcune delle quali sono dup, alcune delle quali sono inappropriate per SO, alcune delle quali potrebbero essere delle buone domande. Stai chiedendo se Python non rilascia la memoria, in quali circostanze è possibile/non può, qual è il meccanismo sottostante, perché è stato progettato in quel modo, se ci sono soluzioni alternative o qualcos'altro interamente? – abarnert
@abarnert Ho combinato sottoquestioni simili. Per rispondere alle tue domande: so che Python rilascia qualche memoria nel sistema operativo, ma perché non tutto e perché la quantità che fa. Se ci sono circostanze in cui non può, perché? Che soluzioni alternative pure. – Jared