Taille en mémoire d'une structure Python

118

Existe-t-il une référence pour la taille de la mémoire de la structure de données Python sur les plates-formes 32 et 64 bits?

Sinon, ce serait bien de l'avoir sur SO. Plus c'est exhaustif, mieux c'est! Alors, combien d'octets sont utilisés par les structures Python suivantes (en fonction du lenet du type de contenu le cas échéant)?

  • int
  • float
  • référence
  • str
  • chaîne unicode
  • tuple
  • list
  • dict
  • set
  • array.array
  • numpy.array
  • deque
  • objet classes de nouveau style
  • objet classes à l'ancienne
  • ... et tout ce que j'oublie!

(Pour les conteneurs qui ne conservent que des références à d'autres objets, nous ne voulons évidemment pas compter la taille de l'élément eux-mêmes, car il pourrait être partagé.)

De plus, y a-t-il un moyen d'obtenir la mémoire utilisée par un objet à l'exécution (récursivement ou non)?

LeMiz
la source
De nombreuses explications utiles peuvent être trouvées ici stackoverflow.com/questions/1059674/python-memory-model . Je voudrais cependant voir un aperçu plus systématique
LeMiz
3
Pour un tableau NumPy a, utilisez a.nbytes.
Sera
Si vous êtes intéressé par une vue graphique de cela, j'en ai fait un tracé une fois: stackoverflow.com/a/30008338/2087463
tmthydvnprt

Réponses:

145

La recommandation d' une question précédente à ce sujet était d'utiliser sys.getsizeof () , en citant:

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

Vous pouvez adopter cette approche:

>>> 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

30/09/2012

python 2.7 (linux, 32 bits):

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 bits)

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

01/08/2016

OSX, Python 2.7.10 (par défaut, 23 octobre 2015, 19:19:21) [GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.5)] sur darwin

decimal 80
dict 280
float 24
int 24
list 72
object 16
set 232
str 38
tuple 56
unicode 52
Hughdbrown
la source
1
Merci et désolé pour la dupe pour la deuxième question ... dommage que j'utilise 2.5 et non 2.6 ...
LeMiz
J'ai oublié que j'avais une boîte virtuelle avec un ubuntu récent dessus! C'est étrange, sys.getsizeof (dict) est 136 pour moi (python 2.6 fonctionnant sur une vm kubuntu, hébergé par OS X, donc je ne suis sûr de rien)
LeMiz
@LeMiz: Pour moi (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 avril 2009, 01:56:41) [GCC 4.3.3] sur linux2 Tapez "help", "copyright", "credits" ou "license" pour plus d'informations. >>> import sys >>> sys.getsizeof (dict) 436 >>> sys.getsizeof (dict ()) 136
LeMiz
1
ne doivent pas être les valeurs 0, 0.0, ''et u''par souci de cohérence?
SilentGhost
37

J'utilise volontiers pympler pour de telles tâches. Il est compatible avec de nombreuses versions de Python - le asizeofmodule en particulier remonte à 2.2!

Par exemple, en utilisant l'exemple de hughdbrown mais avec from pympler import asizeofau début et print asizeof.asizeof(v)à la fin, je vois (système Python 2.5 sur 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

Il y a clairement une approximation ici, mais je l'ai trouvé très utile pour l'analyse et le réglage de l'empreinte.

Alex Martelli
la source
1
Quelques curiosités: la plupart d'entre vous sont 4 plus élevés; l'objet vaut 0; et décimal est environ 4 fois plus grand par votre estimation.
hughdbrown
1
Oui. Le "4 supérieur" ressemble en fait à "arrondi à un multiple de 8", ce qui, je crois, est correct pour la façon dont malloc se comporte ici. Je ne sais pas pourquoi le décimal est si déformé (avec pympler sur 2.6 également).
Alex Martelli
2
En fait, vous devriez utiliser pympler.asizeof.flatsize () pour obtenir une fonctionnalité similaire à sys.getsizeof (). Il existe également un paramètre align = que vous pouvez utiliser (qui est 8 par défaut comme l'a souligné Alex).
Pankrat
@AlexMartelli Salut Alex! .. Pourquoi la taille minimale d'un caractère en python est de 25 octets. >>> getsizeof('a')donne 25et >>> getsizeof('ab')donne 26`
Grijesh Chauhan
1
Je suppose que la taille est en octets, mais pourquoi elle n'est écrite nulle part, même dans pythonhosted.org/Pympler
Zhomart
35

Ces réponses collectent toutes des informations de taille superficielle. Je soupçonne que les visiteurs de cette question finiront ici par chercher à répondre à la question "Quelle est la taille de cet objet complexe en mémoire?"

Il y a une excellente réponse ici: https://goshippo.com/blog/measure-real-size-any-python-object/

La punchline:

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

Utilisé comme ça:

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

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

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

Si vous voulez connaître plus en détail le modèle de mémoire de Python, il y a un excellent article ici qui contient un extrait de code similaire de «taille totale» dans le cadre d'une explication plus longue: https://code.tutsplus.com/tutorials/understand-how- beaucoup-de-mémoire-votre-utilisation-d'objets-python - cms-25609

Kobold
la source
Cela devrait donc donner la quantité totale de mémoire utilisée, par exemple, par un dict contenant plusieurs tableaux et / ou d'autres dictionnaires?
Charly Empereur-mot
1
@ CharlyEmpereur-mot ouais.
Kobold
Très bonne réponse. Cela ne semble cependant pas fonctionner pour les objets cython compilés. Dans mon cas, cette méthode retourne 96un pointeur vers un objet cython en mémoire
ferdynator
8

Essayez le profileur de mémoire. profileur de mémoire

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
Tampa
la source
1
La précision semble être de 1/100 Mo, soit 10,24 octets. C'est bien pour la macro-analyse, mais je doute qu'une telle précision conduise à une comparaison précise des structures de données posées dans la question.
Zoran Pavlovic
7

Vous pouvez également utiliser le module 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.>

Et:

>>> 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
Omid Raha
la source
0

On peut également utiliser le tracemallocmodule de la bibliothèque standard Python. Cela semble bien fonctionner pour les objets dont la classe est implémentée en C (contrairement à Pympler, par exemple).

zahypeti
la source
-1

Lorsque vous utilisez la dir([object])fonction intégrée, vous pouvez obtenir la __sizeof__fonction intégrée.

>>> a = -1
>>> a.__sizeof__()
24
bonjour_dieu
la source