Dimensioni in memoria di una struttura Python


118

Esiste un riferimento per la dimensione della memoria della struttura dati Python su piattaforme a 32 e 64 bit?

In caso contrario, sarebbe bello averlo su SO. Più esaustivo è, meglio è! Quindi quanti byte vengono utilizzati dalle seguenti strutture Python (a seconda lendel tipo di contenuto e se pertinente)?

  • int
  • float
  • riferimento
  • str
  • stringa unicode
  • tuple
  • list
  • dict
  • set
  • array.array
  • numpy.array
  • deque
  • oggetto classi nuovo stile
  • oggetto classi vecchio stile
  • ... e tutto quello che sto dimenticando!

(Per i contenitori che conservano solo riferimenti ad altri oggetti, ovviamente non vogliamo contare le dimensioni dell'elemento stesso, poiché potrebbe essere condiviso.)

Inoltre, esiste un modo per ottenere la memoria utilizzata da un oggetto in fase di esecuzione (in modo ricorsivo o no)?


Molte spiegazioni utili possono essere trovate qui stackoverflow.com/questions/1059674/python-memory-model . Tuttavia, vorrei vedere una panoramica più sistematica
LeMiz

3
Per un array NumPy a, usa a.nbytes.
Will

Se siete interessati in una visualizzazione grafica di questo, ho fatto un terreno di una volta: stackoverflow.com/a/30008338/2087463
tmthydvnprt

Risposte:


145

La raccomandazione di una domanda precedente su questo era di usare sys.getsizeof () , citando:

>>> import sys
>>> x = 2
>>> sys.getsizeof(x)
14
>>> sys.getsizeof(sys.getsizeof)
32
>>> sys.getsizeof('this')
38
>>> sys.getsizeof('this also')
48

Potresti adottare questo approccio:

>>> import sys
>>> import decimal
>>> 
>>> d = {
...     "int": 0,
...     "float": 0.0,
...     "dict": dict(),
...     "set": set(),
...     "tuple": tuple(),
...     "list": list(),
...     "str": "a",
...     "unicode": u"a",
...     "decimal": decimal.Decimal(0),
...     "object": object(),
... }
>>> for k, v in sorted(d.iteritems()):
...     print k, sys.getsizeof(v)
...
decimal 40
dict 140
float 16
int 12
list 36
object 8
set 116
str 25
tuple 28
unicode 28

2012-09-30

python 2.7 (linux, 32 bit):

decimal 36
dict 136
float 16
int 12
list 32
object 8
set 112
str 22
tuple 24
unicode 32

python 3.3 (linux, 32 bit)

decimal 52
dict 144
float 16
int 14
list 32
object 8
set 112
str 26
tuple 24
unicode 26

2016/08/01

OSX, Python 2.7.10 (predefinito, 23 ottobre 2015, 19:19:21) [GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.5)] su darwin

decimal 80
dict 280
float 24
int 24
list 72
object 16
set 232
str 38
tuple 56
unicode 52

1
Grazie, e scusa per il duplicato della seconda domanda ...
peccato

Dimenticavo di avere una scatola virtuale con sopra un Ubuntu recente! È strano, sys.getsizeof (dict) è 136 per me (python 2.6 in esecuzione su un vm kubuntu, ospitato da OS X, quindi non sono sicuro di nulla)
LeMiz

@LeMiz: per me (Python 2.6, Windows XP SP3), sys.getsizeof (dict) -> 436; sys.getsizeof (dict ()) -> 140
John Machin,

LeMiz-Kubuntu: python2.6 Python 2.6.2 (release26-maint, 19 aprile 2009, 01:56:41) [GCC 4.3.3] su linux2 Digita "help", "copyright", "credits" o "license" per maggiori informazioni. >>> import sys >>> sys.getsizeof (dict) 436 >>> sys.getsizeof (dict ()) 136
LeMiz

1
Non dovrebbero essere i valori 0, 0.0, ''e u''per la coerenza?
SilentGhost

37

Ho usato felicemente Pympler per questi compiti. È compatibile con molte versioni di Python - il asizeofmodulo in particolare risale alla 2.2!

Ad esempio, usando l'esempio di hughdbrown ma con from pympler import asizeofall'inizio e print asizeof.asizeof(v)alla fine, vedo (sistema Python 2.5 su MacOSX 10.5):

$ python pymp.py 
set 120
unicode 32
tuple 32
int 16
decimal 152
float 16
list 40
object 0
dict 144
str 32

Chiaramente c'è qualche approssimazione qui, ma l'ho trovata molto utile per l'analisi e la regolazione dell'impronta.


1
Alcune curiosità: la maggior parte di voi numeri sono 4 superiori; l'oggetto è 0; e il decimale è circa 4 volte più grande della tua stima.
hughdbrown

1
Sì. Il "4 più alto" in realtà sembra per lo più "arrotondamento per eccesso a un multiplo di 8" che credo sia corretto per il modo in cui malloc si comporta qui. Non ho idea del perché i decimali siano così distorti (anche con pympler su 2.6).
Alex Martelli

2
In realtà, dovresti usare pympler.asizeof.flatsize () per ottenere una funzionalità simile a sys.getsizeof (). C'è anche un parametro align = che puoi usare (che è 8 per impostazione predefinita, come ha sottolineato Alex).
Pankrat

@AlexMartelli Ciao Alex! .. Perché la dimensione minima di un carattere in Python è di 25 byte. >>> getsizeof('a')25e >>> getsizeof('ab')26`
Grijesh Chauhan

1
Suppongo che la dimensione sia in byte, ma perché non è scritta da nessuna parte, anche in pythonhosted.org/Pympler
Zhomart

35

Tutte queste risposte raccolgono informazioni di dimensioni ridotte. Sospetto che i visitatori di questa domanda finiranno qui cercando di rispondere alla domanda: "Quanto è grande questo oggetto complesso nella memoria?"

C'è un'ottima risposta qui: https://goshippo.com/blog/measure-real-size-any-python-object/

La battuta finale:

import sys

def get_size(obj, seen=None):
    """Recursively finds size of objects"""
    size = sys.getsizeof(obj)
    if seen is None:
        seen = set()
    obj_id = id(obj)
    if obj_id in seen:
        return 0
    # Important mark as seen *before* entering recursion to gracefully handle
    # self-referential objects
    seen.add(obj_id)
    if isinstance(obj, dict):
        size += sum([get_size(v, seen) for v in obj.values()])
        size += sum([get_size(k, seen) for k in obj.keys()])
    elif hasattr(obj, '__dict__'):
        size += get_size(obj.__dict__, seen)
    elif hasattr(obj, '__iter__') and not isinstance(obj, (str, bytes, bytearray)):
        size += sum([get_size(i, seen) for i in obj])
    return size

Usato così:

In [1]: get_size(1)
Out[1]: 24

In [2]: get_size([1])
Out[2]: 104

In [3]: get_size([[1]])
Out[3]: 184

Se vuoi conoscere più a fondo il modello di memoria di Python, c'è un ottimo articolo qui che ha uno snippet di codice simile a "dimensione totale" come parte di una spiegazione più lunga: https://code.tutsplus.com/tutorials/understand-how- tanto di memoria-your-python-oggetti-uso - CMS-25609


Quindi questo dovrebbe produrre la quantità totale di memoria utilizzata, ad esempio, da un dict contenente più array e / o altri dict?
Charly Empereur-mot

1
@ CharlyEmpereur-mot yep.
Kobold

Bella risposta. Tuttavia non sembra funzionare per oggetti cython compilati. Nel mio caso questo metodo restituisce 96un puntatore a un oggetto cython in memoria
ferdynator

8

Prova il profiler della memoria. profiler della memoria

Line #    Mem usage  Increment   Line Contents
==============================================
     3                           @profile
     4      5.97 MB    0.00 MB   def my_func():
     5     13.61 MB    7.64 MB       a = [1] * (10 ** 6)
     6    166.20 MB  152.59 MB       b = [2] * (2 * 10 ** 7)
     7     13.61 MB -152.59 MB       del b
     8     13.61 MB    0.00 MB       return a

1
La precisione sembra essere 1 / 100MB o 10,24 byte. Questo va bene per la macroanalisi, ma dubito che una tale precisione porterebbe a un confronto accurato delle strutture di dati come richiesto nella domanda.
Zoran Pavlovic

7

Inoltre puoi usare il modulo guppy .

>>> from guppy import hpy; hp=hpy()
>>> hp.heap()
Partition of a set of 25853 objects. Total size = 3320992 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0  11731  45   929072  28    929072  28 str
     1   5832  23   469760  14   1398832  42 tuple
     2    324   1   277728   8   1676560  50 dict (no owner)
     3     70   0   216976   7   1893536  57 dict of module
     4    199   1   210856   6   2104392  63 dict of type
     5   1627   6   208256   6   2312648  70 types.CodeType
     6   1592   6   191040   6   2503688  75 function
     7    199   1   177008   5   2680696  81 type
     8    124   0   135328   4   2816024  85 dict of class
     9   1045   4    83600   3   2899624  87 __builtin__.wrapper_descriptor
<90 more rows. Type e.g. '_.more' to view.>

E:

>>> hp.iso(1, [1], "1", (1,), {1:1}, None)
Partition of a set of 6 objects. Total size = 560 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0      1  17      280  50       280  50 dict (no owner)
     1      1  17      136  24       416  74 list
     2      1  17       64  11       480  86 tuple
     3      1  17       40   7       520  93 str
     4      1  17       24   4       544  97 int
     5      1  17       16   3       560 100 types.NoneType

0

Si può anche fare uso del tracemallocmodulo dalla libreria standard di Python. Sembra funzionare bene per oggetti la cui classe è implementata in C (a differenza di Pympler, per esempio).


-1

Quando si utilizza la dir([object])funzione incorporata, è possibile ottenere la __sizeof__funzione incorporata.

>>> a = -1
>>> a.__sizeof__()
24
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.