In-Memory-Größe einer Python-Struktur

118

Gibt es eine Referenz für die Speichergröße der Python-Datenstruktur auf 32- und 64-Bit-Plattformen?

Wenn nicht, wäre es schön, es auf SO zu haben. Je umfassender desto besser! Wie viele Bytes werden von den folgenden Python-Strukturen verwendet (abhängig vom lenund dem Inhaltstyp, falls relevant)?

  • int
  • float
  • Referenz
  • str
  • Unicode-Zeichenfolge
  • tuple
  • list
  • dict
  • set
  • array.array
  • numpy.array
  • deque
  • Klassenobjekt neuen Stils
  • Old-Style-Klassenobjekt
  • ... und alles was ich vergesse!

(Bei Containern, die nur Verweise auf andere Objekte enthalten, möchten wir natürlich nicht die Größe des Elements selbst zählen, da es möglicherweise gemeinsam genutzt wird.)

Gibt es außerdem eine Möglichkeit, den von einem Objekt zur Laufzeit verwendeten Speicher abzurufen (rekursiv oder nicht)?

LeMiz
quelle
Viele hilfreiche Erklärungen finden Sie hier stackoverflow.com/questions/1059674/python-memory-model . Ich würde jedoch gerne einen systematischeren Überblick sehen
LeMiz
3
aVerwenden Sie für ein NumPy-Array a.nbytes.
Will
Wenn Sie an einer grafischen Ansicht interessiert sind, habe ich sie einmal geplottet
tmthydvnprt

Antworten:

145

Die Empfehlung einer früheren Frage dazu lautete, sys.getsizeof () zu verwenden und zitierte:

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

Sie könnten diesen Ansatz wählen:

>>> 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 (Standard, 23. Oktober 2015, 19:19:21) [GCC 4.2.1-kompatibles Apple LLVM 7.0.0 (clang-700.0.59.5)] auf Darwin

decimal 80
dict 280
float 24
int 24
list 72
object 16
set 232
str 38
tuple 56
unicode 52
hughdbrown
quelle
1
Danke und Entschuldigung für den Betrug für die zweite Frage ... schade, ich benutze 2.5 und nicht 2.6 ...
LeMiz
Ich habe vergessen, dass ich eine virtuelle Box mit einem aktuellen Ubuntu hatte! Das ist seltsam, sys.getsizeof (dict) ist 136 für mich (Python 2.6 läuft auf einem Kubuntu VM, das von OS X gehostet wird, daher bin ich mir über nichts sicher)
LeMiz
@LeMiz: Für mich (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. April 2009, 01:56:41) [GCC 4.3.3] unter Linux2 Geben Sie "Hilfe", "Copyright", "Credits" oder "Lizenz" ein. für mehr Informationen. >>> sys importieren >>> sys.getsizeof (dict) 436 >>> sys.getsizeof (dict ()) 136
LeMiz
1
sollte nicht die Werte 0, 0.0, ''und u''für Konsistenz?
SilentGhost
37

Ich habe Pympler gerne für solche Aufgaben verwendet. Es ist mit vielen Versionen von Python kompatibel - insbesondere das asizeofModul geht auf 2.2 zurück!

Am Beispiel von hughdbrown, aber mit from pympler import asizeofam Anfang und print asizeof.asizeof(v)am Ende, sehe ich (System Python 2.5 unter 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

Natürlich gibt es hier einige Annäherungen, aber ich fand es sehr nützlich für die Analyse und Optimierung des Fußabdrucks.

Alex Martelli
quelle
1
Einige Kuriositäten: Die meisten von Ihnen sind 4 höher; Objekt ist 0; und die Dezimalstelle ist nach Ihrer Schätzung etwa viermal größer.
Hughdbrown
1
Ja. Die "4 höher" sehen eigentlich meistens aus wie "Aufrunden auf ein Vielfaches von 8", was meiner Meinung nach für das Verhalten von Malloc hier richtig ist. Keine Ahnung, warum die Dezimalstelle so verzerrt wird (auch mit Pympler auf 2.6).
Alex Martelli
2
Eigentlich sollten Sie pympler.asizeof.flatsize () verwenden, um eine ähnliche Funktionalität wie sys.getsizeof () zu erhalten. Es gibt auch einen align = -Parameter, den Sie verwenden können (standardmäßig 8, wie Alex betont hat).
Pankrat
@ AlexMartelli Hallo Alex! .. Warum die Mindestgröße eines Zeichens in Python 25 Bytes beträgt. >>> getsizeof('a')gibt 25und >>> getsizeof('ab')gibt 26`
Grijesh Chauhan
1
Ich nehme an, die Größe ist in Bytes angegeben, aber warum wird sie nirgendwo geschrieben, auch nicht in pythonhosted.org/Pympler
Zhomart
34

Diese Antworten sammeln alle Informationen zu geringer Größe. Ich vermute, dass Besucher dieser Frage hier landen werden, um die Frage zu beantworten: "Wie groß ist dieses komplexe Objekt im Gedächtnis?"

Hier gibt es eine gute Antwort: https://goshippo.com/blog/measure-real-size-any-python-object/

Die Pointe:

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

So verwendet:

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

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

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

Wenn Sie das Speichermodell von Python genauer kennenlernen möchten, finden Sie hier einen großartigen Artikel mit einem ähnlichen Codeausschnitt in "Gesamtgröße" als Teil einer längeren Erklärung: https://code.tutsplus.com/tutorials/understand-how- Viel-Speicher-deine-Python-Objekte-verwenden - cms-25609

Kobold
quelle
Dies sollte also die Gesamtmenge an Speicher ergeben, die beispielsweise von einem Diktat mit mehreren Arrays und / oder anderen Diktaten verwendet wird.
Charly Empereur-mot
1
@ CharlyEmpereur-mot yep.
Kobold
Gute Antwort. Es scheint jedoch nicht für kompilierte Cython-Objekte zu funktionieren. In meinem Fall gibt diese Methode 96für einen Zeiger auf ein In-Memory-Cython-Objekt zurück
Ferdynator
8

Versuchen Sie es mit Memory Profiler. Speicherprofiler

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
quelle
1
Die Genauigkeit scheint 1 / 100MB oder 10,24 Bytes zu betragen. Dies ist für die Makroanalyse in Ordnung, aber ich bezweifle, dass eine solche Genauigkeit zu einem genauen Vergleich der in der Frage gestellten Datenstrukturen führen würde.
Zoran Pavlovic
7

Sie können auch das Guppy- Modul verwenden.

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

Und:

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

Man kann das tracemallocModul auch aus der Python-Standardbibliothek verwenden. Es scheint gut für Objekte zu funktionieren, deren Klasse in C implementiert ist (im Gegensatz zu Pympler zum Beispiel).

zahypeti
quelle
-1

Wenn Sie die dir([object])integrierte Funktion verwenden, können Sie __sizeof__die integrierte Funktion abrufen.

>>> a = -1
>>> a.__sizeof__()
24
hallo_gott
quelle