2015-10-23 10 views
6

Sono curioso di sapere come differisce la gestione della memoria tra Bytearray e l'elenco in Python.Differenza tra Bytearray e List in Python

Ho trovato alcune domande come Difference between bytearray and list ma non esattamente rispondendo alla mia domanda.

Domande precisamente ...

from array import array 
>>> x = array("B", (1,2,3,4)) 
>>> x.__sizeof__() 
36 
>>> y = bytearray((1,2,3,4)) 
>>> y.__sizeof__() 
32 
>>> z = [1,2,3,4] 
>>> z.__sizeof__() 
36 

Come si vede v'è una differenza di dimensioni tra lista/array.array (36 byte per 4 elementi) e una matrice di byte (32 byte per 4 elementi). Qualcuno può spiegarmi perché è questo? Ha senso che l'array di byte occupi 32 byte di memoria per gli elementi 4(4 * 8 == 32), ma come può essere interpretato per elenco e array.array?

# Lets take the case of bytearray (which makes more sense to me at least :p) 
for i in y: 
     print(i, ": ", id(i)) 

1 : 499962320 
2 : 499962336 #diff is 16 units 
3 : 499962352 #diff is 16 units 
4 : 499962368 #diff is 16 units 

Perché la differenza tra due elementi contigui differiscono da 16 unità qui, quando ciascun elemento occupa solo 8 byte. Significa che ogni puntatore dell'indirizzo di memoria punta a un nibble?

Inoltre, quali sono i criteri per l'allocazione di memoria per un intero? Ho letto che Python assegnerà più memoria in base al valore dell'intero (correggimi se ho torto) come maggiore è il numero più memoria.

Esempio:

>>> y = 10 
>>> y.__sizeof__() 
14 
>>> y = 1000000 
>>> y.__sizeof__() 
16 
>>> y = 10000000000000 
>>> y.__sizeof__() 
18 

ciò che è il criterio che Python alloca la memoria?

E perché Python occupa molta più memoria mentre C occupa solo 8 byte (la mia è una macchina a 64 bit)? quando sono perfettamente al di sotto dell'intervallo del numero intero (2 ** 64)?

Metadati:

Python versione:'3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:43:06) [MSC v.1600 32 bit (Intel)]'

macchina arco: 64 bit

PS: Gentilmente mi guida per un buon articolo in cui la gestione della memoria Python è spiegato meglio. Avevo passato quasi un'ora a capire queste cose e ho finito per fare questa domanda in SO. :(

+2

Buona domanda, svalutato. Ehi, sei fortunato: sulla mia macchina Linux Xubuntu a 64 bit CPython 3.4.3 'y .__ sizeof __()' mi dà '28' per' y = 10', lo stesso per 'y = 1M',' 32' per 'y = 10000000000000' – Pynchia

+0

Hi @Pynchia, Mine è un python a 32 bit sebbene la mia macchina sia a 64 bit. Non sono sicuro, ma quella potrebbe essere la ragione. Aspettiamo qualcuno per chiarire. –

risposta

1

Non sto sostenendo questo è risposta completa, ma ci sono alcuni suggerimenti per comprendere questo.

bytearray è una sequenza di byte e list è una sequenza di riferimenti a oggetti. Così [1,2,3] effettivamente detiene puntatori di memoria a quei numeri interi che vengono memorizzati nella memoria altrove. per calcolare il consumo totale di memoria di una struttura della lista, siamo in grado di fare questo (sto usando sys.getsizeof ovunque ulteriormente, si sta chiamando __sizeof__ più in testa GC)

>>> x = [1,2,3] 
>>> sum(map(getsizeof, x)) + getsizeof(x) 
172 

risultato può essere d ifferent su diverse macchine.

Inoltre, un'occhiata a questo:

>> getsizeof([]) 
64 

Questo perché le liste sono mutabili. Per essere veloce, questa struttura alloca un po 'di memoria range per memorizzare riferimenti ad oggetti (più un po' di memoria per meta, come la lunghezza della lista). Quando si aggiungono elementi, le celle di memoria successive vengono riempite con riferimenti a tali elementi. Quando non c'è spazio per memorizzare nuovi oggetti, viene assegnata una nuova gamma più ampia, i dati esistenti vengono copiati e quelli vecchi rilasciati. Questo chiamato array dinamici.

È possibile osservare questo comportamento, eseguendo questo codice.

import sys 
data=[] 
n=15 
for k in range(n): 
    a = len(data) 
    b = sys.getsizeof(data) 
    print('Length: {0:3d}; Size in bytes: {1:4d}'.format(a, b)) 
    data.append(None) 

I miei risultati:

Length: 0; Size in bytes: 64 
Length: 1; Size in bytes: 96 
Length: 2; Size in bytes: 96 
Length: 3; Size in bytes: 96 
Length: 4; Size in bytes: 96 
Length: 5; Size in bytes: 128 
Length: 6; Size in bytes: 128 
Length: 7; Size in bytes: 128 
Length: 8; Size in bytes: 128 
Length: 9; Size in bytes: 192 
Length: 10; Size in bytes: 192 
Length: 11; Size in bytes: 192 
Length: 12; Size in bytes: 192 
Length: 13; Size in bytes: 192 
Length: 14; Size in bytes: 192 

Possiamo vedere che ci sono 64 byte è stato utilizzato per memorizzare 8 indirizzi di memoria (64 bit ciascuno).

Quasi lo stesso vale per bytearray() (modificare la seconda riga su data = bytearray() e aggiungere 1 nell'ultimo).

Length: 0; Size in bytes: 56 
Length: 1; Size in bytes: 58 
Length: 2; Size in bytes: 61 
Length: 3; Size in bytes: 61 
Length: 4; Size in bytes: 63 
Length: 5; Size in bytes: 63 
Length: 6; Size in bytes: 65 
Length: 7; Size in bytes: 65 
Length: 8; Size in bytes: 68 
Length: 9; Size in bytes: 68 
Length: 10; Size in bytes: 68 
Length: 11; Size in bytes: 74 
Length: 12; Size in bytes: 74 
Length: 13; Size in bytes: 74 
Length: 14; Size in bytes: 74 

La differenza è che la memoria ora viene utilizzata per contenere valori di byte effettivi, non puntatori.

Spero che ti aiuti a indagare ulteriormente.

+0

Ciao @ anti1869, grazie per il tuo commento. È molto esauriente e utile. Ma sto seguendo le domande nel tuo commento. Non sono in grado di aggiungere tutte le informazioni qui e quindi aggiungere un altro commento sotto. Grazie –

+0

È comprensibile per l'elenco come da spiegazione, ma perché la dimensione dell'array di byte è iniziata con 56. e perché è stabile dopo aver raggiunto 74? Inoltre, sarebbe lieto se tu possa fornire maggiori informazioni sulla dimensione iniziale se 64 e 56. Grazie –

+0

Controlla che il codice sorgente delle strutture dati. Lì vedrai la struttura interna del contenitore e cosa allocerà la memoria al momento dell'inizializzazione. Inoltre c'è un algoritmo di crescita visibile molto chiaramente. https://github.com/python/cpython/blob/master/Objects/listobject.c – anti1869