2014-04-10 34 views
8

In che modo la RAM richiesta per memorizzare i dati in memoria è paragonabile allo spazio su disco necessario per memorizzare gli stessi dati in un file? O non esiste una correlazione generalizzata?Dimensioni dei dati in memoria rispetto a disco

Ad esempio, dire che ho semplicemente un miliardo di valori in virgola mobile. Memorizzati in forma binaria, sarebbero 4 miliardi di byte o 3,7 GB su disco (escluse le intestazioni e simili). Quindi dì che ho letto quei valori in una lista in Python ... quanta RAM dovrei aspettarmi da richiedere?

+0

Più RAM! C'è una lista in testa, tra le altre cose. Se sei preoccupato, a) scopri, e b) considera solo la memorizzazione dei dati grezzi in memoria e la decompressione al volo (dipende da cosa stai facendo con esso). – Ryan

+2

Correlati: http: // stackoverflow.it/a/994010/846892 –

+0

Il mio primo pensiero è che ci vorrà un po 'prima che l'utente attenda che tutti i dati siano stati caricati nella RAM. –

risposta

3

Python oggetto Informazioni Dimensione

Se i dati sono memorizzati in un oggetto Python, ci sarà un po 'più di dati collegati ai dati effettivi in ​​memoria.

Questo può essere facilmente testato.

The size of data in various forms

È interessante notare come, in un primo momento, l'overhead dell'oggetto pitone è significativo per piccoli dati, ma diventa rapidamente trascurabile.

Qui è il codice ipython utilizzato per generare la trama

%matplotlib inline 
import random 
import sys 
import array 
import matplotlib.pyplot as plt 

max_doubles = 10000 

raw_size = [] 
array_size = [] 
string_size = [] 
list_size = [] 
set_size = [] 
tuple_size = [] 
size_range = range(max_doubles) 

# test double size 
for n in size_range: 
    double_array = array.array('d', [random.random() for _ in xrange(n)]) 
    double_string = double_array.tostring() 
    double_list = double_array.tolist() 
    double_set = set(double_list) 
    double_tuple = tuple(double_list) 

    raw_size.append(double_array.buffer_info()[1] * double_array.itemsize) 
    array_size.append(sys.getsizeof(double_array)) 
    string_size.append(sys.getsizeof(double_string)) 
    list_size.append(sys.getsizeof(double_list)) 
    set_size.append(sys.getsizeof(double_set)) 
    tuple_size.append(sys.getsizeof(double_tuple)) 

# display 
plt.figure(figsize=(10,8)) 
plt.title('The size of data in various forms', fontsize=20) 
plt.xlabel('Data Size (double, 8 bytes)', fontsize=15) 
plt.ylabel('Memory Size (bytes)', fontsize=15) 
plt.loglog(
    size_range, raw_size, 
    size_range, array_size, 
    size_range, string_size, 
    size_range, list_size, 
    size_range, set_size, 
    size_range, tuple_size 
) 
plt.legend(['Raw (Disk)', 'Array', 'String', 'List', 'Set', 'Tuple'], fontsize=15, loc='best') 
+1

Questa risposta non è corretta. La documentazione di sys.getsizeof afferma che "Viene preso in considerazione solo il consumo di memoria direttamente attribuito all'oggetto, non il consumo di memoria degli oggetti a cui fa riferimento." Quindi hai solo calcolato la memoria allocata nei contenitori e non hai considerato la memoria aggiuntiva allocata per gli oggetti numerici stessi. –

+1

Hai una raccomandazione su come determinare l'allocazione di memoria completa? Rifarò la trama! – tmthydvnprt

+0

Penso che sia necessario aggiungere 'len (double_list) * sys.getsizeof (1.0)' alla dimensione della memoria segnalata per 'list',' set' e 'tuple'. Probabilmente c'è una memoria aggiuntiva necessaria per gestire le allocazioni, ma non so come misurarla e dovrebbe essere trascurabile. –

1

Nell'elenco Python pianura, ogni numero doppiato richiede almeno 32 byte di memoria, ma solo 8 byte vengono utilizzati per memorizzare l'attuale numero, il resto è necessario per supportare la natura dinamica di Python.

L'oggetto galleggiante utilizzato in CPython è definito in floatobject.h:

typedef struct { 
    PyObject_HEAD 
    double ob_fval; 
} PyFloatObject; 

dove PyObject_HEAD è a macro that expands al PyObject struct:

typedef struct _object { 
    Py_ssize_t ob_refcnt; 
    struct _typeobject *ob_type; 
} PyObject; 

Pertanto, ogni oggetto in virgola mobile in esercizi Python due pointer- campi di dimensioni (quindi ognuno richiede 8 byte su un'architettura a 64 bit) oltre al doppio di 8 byte, fornendo 24 byte di memoria allocata per numero. Questo è confermato da sys.getsizeof(1.0) == 24.

Ciò significa che un elenco di n doppie in Python richiede almeno 8*n byte di memoria per memorizzare solo i puntatori (PyObject*) agli oggetti numerici e ciascun oggetto numero richiede ulteriori 24 byte. Per provarlo, provare a eseguire le seguenti righe nel Python REPL:

>>> import math 
>>> list_of_doubles = [math.sin(x) for x in range(10*1000*1000)] 

e vedere l'utilizzo della memoria dell'interprete Python (ho ottenuto circa 350 MB di memoria allocata sul mio computer x86-64). Si noti che se si è tentato:

>>> list_of_doubles = [1.0 for __ in range(10*1000*1000)] 

si otterrebbe solo circa 80 MB, in quanto tutti gli elementi della lista si riferiscono alla stessa istanza del numero in virgola mobile 1.0.