Wie bestimme ich die Größe eines Objekts in Python?

682

Ich möchte wissen, wie man die Größe von Objekten wie einer Zeichenfolge, einer Ganzzahl usw. in Python ermittelt.

Verwandte Frage: Wie viele Bytes pro Element enthält eine Python-Liste (Tupel)?

Ich verwende eine XML-Datei, die Größenfelder enthält, die die Größe des Werts angeben. Ich muss dieses XML analysieren und meine Codierung durchführen. Wenn ich den Wert eines bestimmten Feldes ändern möchte, überprüfe ich das Größenfeld dieses Werts. Hier möchte ich vergleichen, ob der neue Wert, den ich eingeben möchte, dieselbe Größe wie in XML hat. Ich muss die Größe des neuen Werts überprüfen. Im Falle einer Zeichenfolge kann ich sagen, dass es die Länge ist. Aber im Falle von int, float usw. bin ich verwirrt.

user46646
quelle

Antworten:

665

Verwenden Sie einfach die im sysModul definierte Funktion sys.getsizeof .

sys.getsizeof(object[, default])::

Gibt die Größe eines Objekts in Bytes zurück. Das Objekt kann ein beliebiger Objekttyp sein. Alle integrierten Objekte geben korrekte Ergebnisse zurück, dies muss jedoch nicht für Erweiterungen von Drittanbietern gelten, da es implementierungsspezifisch ist.

Mit dem defaultArgument kann ein Wert definiert werden, der zurückgegeben wird, wenn der Objekttyp keine Mittel zum Abrufen der Größe bietet und a verursachen würde TypeError.

getsizeofRuft die __sizeof__Methode des Objekts auf und fügt einen zusätzlichen Garbage Collector-Overhead hinzu, wenn das Objekt vom Garbage Collector verwaltet wird.

Anwendungsbeispiel in Python 3.0:

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

Wenn Sie in Python <2.6 sind und nicht haben sys.getsizeof, können Sie stattdessen dieses umfangreiche Modul verwenden. Ich habe es aber nie benutzt.

nosklo
quelle
180
Bitte fügen Sie dem Haftungsausschluss hinzu, dass dies nicht für verschachtelte Objekte oder verschachtelte Dikte oder Dikte in Listen usw. gilt.
JohnnyM
8
@ChaimG das liegt daran, dass jedes Objekt nur 32 Bytes verwendet !! Der Rest sind Verweise auf andere Objekte. Wenn Sie die referenzierten Objekte berücksichtigen möchten, müssen Sie die __sizeof__Methode für Ihre Klasse definieren. Die eingebaute dictPython-Klasse definiert es, deshalb erhalten Sie das richtige Ergebnis, wenn Sie ein Objekt vom Typ verwenden dict.
Nosklo
19
Der Haftungsausschluss und die Ausnahmen von dieser Arbeit decken fast alle Anwendungsfälle ab, bei denen die getsizeofFunktion von geringem Wert ist.
Robino
7
Warum wird die Ganzzahl 2 in 24 Bytes gespeichert?
Saher Ahwal
4
@ SaherAhwal es ist nicht nur eine ganze Zahl, sondern ein vollständiges Objekt mit Methoden, Attributen, Adressen ...
nosklo
369

Wie bestimme ich die Größe eines Objekts in Python?

Die Antwort "Verwenden Sie einfach sys.getsizeof" ist keine vollständige Antwort.

Diese Antwort funktioniert direkt für integrierte Objekte, berücksichtigt jedoch nicht, was diese Objekte enthalten können, insbesondere welche Typen wie benutzerdefinierte Objekte, Tupel, Listen, Diktate und Mengen enthalten. Sie können sich gegenseitig Instanzen sowie Zahlen, Zeichenfolgen und andere Objekte enthalten.

Eine vollständigere Antwort

Unter Verwendung von 64-Bit-Python 3.6 aus der Anaconda-Distribution mit sys.getsizeof habe ich die Mindestgröße der folgenden Objekte festgelegt und festgestellt, dass Mengen und Diktate Speicherplatz vorab zuweisen, sodass leere Objekte erst nach einer festgelegten Menge wieder wachsen (was möglicherweise der Fall ist) variieren je nach Implementierung der Sprache):

Python 3:

Empty
Bytes  type        scaling notes
28     int         +4 bytes about every 30 powers of 2
37     bytes       +1 byte per additional byte
49     str         +1-4 per additional character (depending on max width)
48     tuple       +8 per additional item
64     list        +8 for each additional
224    set         5th increases to 736; 21nd, 2272; 85th, 8416; 341, 32992
240    dict        6th increases to 368; 22nd, 1184; 43rd, 2280; 86th, 4704; 171st, 9320
136    func def    does not include default args and other attrs
1056   class def   no slots 
56     class inst  has a __dict__ attr, same scaling as dict above
888    class def   with slots
16     __slots__   seems to store in mutable tuple-like structure
                   first slot grows to 48, and so on.

Wie interpretieren Sie das? Angenommen, Sie haben ein Set mit 10 Artikeln. Wenn jedes Element jeweils 100 Byte umfasst, wie groß ist die gesamte Datenstruktur? Der Satz ist 736 selbst, da er einmal auf 736 Bytes skaliert wurde. Dann addieren Sie die Größe der Elemente, sodass insgesamt 1736 Byte vorhanden sind

Einige Einschränkungen für Funktions- und Klassendefinitionen:

Beachten Sie, dass jede Klassendefinition eine Proxy- __dict__Struktur (48 Byte) für Klassenattrs hat. Jeder Slot hat einen Deskriptor (wie a property) in der Klassendefinition.

Geschlitzte Instanzen beginnen mit 48 Bytes in ihrem ersten Element und erhöhen sich um jeweils 8 Bytes. Nur leere Objekte mit Schlitz haben 16 Bytes, und eine Instanz ohne Daten macht wenig Sinn.

Außerdem enthält jede Funktionsdefinition Codeobjekte, möglicherweise Dokumentzeichenfolgen, und andere mögliche Attribute, sogar a __dict__.

Beachten Sie auch, dass wir verwenden, sys.getsizeof()weil wir uns um die marginale Speicherplatznutzung kümmern, einschließlich des Speicherbereinigungsaufwands für das Objekt aus den Dokumenten :

getizeof () ruft die __sizeof__Methode des Objekts auf und fügt einen zusätzlichen Garbage Collector-Overhead hinzu, wenn das Objekt vom Garbage Collector verwaltet wird.

Beachten Sie auch, dass das Ändern der Größe von Listen (z. B. das wiederholte Anhängen an Listen) dazu führt, dass sie Speicherplatz vorab zuweisen, ähnlich wie bei Sätzen und Diktaten. Aus dem Quellcode listobj.c :

    /* This over-allocates proportional to the list size, making room
     * for additional growth.  The over-allocation is mild, but is
     * enough to give linear-time amortized behavior over a long
     * sequence of appends() in the presence of a poorly-performing
     * system realloc().
     * The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
     * Note: new_allocated won't overflow because the largest possible value
     *       is PY_SSIZE_T_MAX * (9 / 8) + 6 which always fits in a size_t.
     */
    new_allocated = (size_t)newsize + (newsize >> 3) + (newsize < 9 ? 3 : 6);

Historische Daten

Python 2.7-Analyse, bestätigt mit guppy.hpyund sys.getsizeof:

Bytes  type        empty + scaling notes
24     int         NA
28     long        NA
37     str         + 1 byte per additional character
52     unicode     + 4 bytes per additional character
56     tuple       + 8 bytes per additional item
72     list        + 32 for first, 8 for each additional
232    set         sixth item increases to 744; 22nd, 2280; 86th, 8424
280    dict        sixth item increases to 1048; 22nd, 3352; 86th, 12568 *
120    func def    does not include default args and other attrs
64     class inst  has a __dict__ attr, same scaling as dict above
16     __slots__   class with slots has no dict, seems to store in 
                   mutable tuple-like structure.
904    class def   has a proxy __dict__ structure for class attrs
104    old class   makes sense, less stuff, has real dict though.

Beachten Sie, dass Wörterbücher ( aber keine Mengen ) in Python 3.6 eine kompaktere Darstellung erhalten

Ich denke, 8 Bytes pro zusätzlichem Referenzelement sind auf einem 64-Bit-Computer sehr sinnvoll. Diese 8 Bytes zeigen auf die Stelle im Speicher, an der sich das enthaltene Element befindet. Die 4 Bytes haben eine feste Breite für Unicode in Python 2, wenn ich mich richtig erinnere, aber in Python 3 wird str zu einem Unicode mit einer Breite, die der maximalen Breite der Zeichen entspricht.

(Weitere Informationen zu Slots finden Sie in dieser Antwort. )

Eine vollständigere Funktion

Wir wollen eine Funktion, die die Elemente in Listen, Tupeln, Mengen, Diktaten obj.__dict__, und obj.__slots__anderen Dingen durchsucht, an die wir vielleicht noch nicht gedacht haben.

Wir möchten gc.get_referentsuns bei dieser Suche darauf verlassen, dass sie auf C-Ebene funktioniert (was sie sehr schnell macht). Der Nachteil ist, dass get_referents redundante Mitglieder zurückgeben kann. Daher müssen wir sicherstellen, dass wir nicht doppelt zählen.

Klassen, Module und Funktionen sind Singletons - sie existieren einmal im Speicher. Wir sind nicht so an ihrer Größe interessiert, da wir nicht viel gegen sie tun können - sie sind Teil des Programms. Wir vermeiden es also, sie zu zählen, wenn auf sie verwiesen wird.

Wir werden eine schwarze Liste von Typen verwenden, damit wir nicht das gesamte Programm in unsere Größenanzahl einbeziehen.

import sys
from types import ModuleType, FunctionType
from gc import get_referents

# Custom objects know their class.
# Function objects seem to know way too much, including modules.
# Exclude modules as well.
BLACKLIST = type, ModuleType, FunctionType


def getsize(obj):
    """sum size of object & members."""
    if isinstance(obj, BLACKLIST):
        raise TypeError('getsize() does not take argument of type: '+ str(type(obj)))
    seen_ids = set()
    size = 0
    objects = [obj]
    while objects:
        need_referents = []
        for obj in objects:
            if not isinstance(obj, BLACKLIST) and id(obj) not in seen_ids:
                seen_ids.add(id(obj))
                size += sys.getsizeof(obj)
                need_referents.append(obj)
        objects = get_referents(*need_referents)
    return size

Um dies mit der folgenden Whitelist-Funktion zu vergleichen, wissen die meisten Objekte, wie sie sich zum Zwecke der Speicherbereinigung selbst durchlaufen müssen (was ungefähr das ist, wonach wir suchen, wenn wir wissen möchten, wie teuer bestimmte Objekte im Speicher sind. Diese Funktionalität wird von verwendet gc.get_referents.) Diese Maßnahme wird jedoch einen viel größeren Umfang haben, als wir beabsichtigt hatten, wenn wir nicht vorsichtig sind.

Zum Beispiel wissen Funktionen ziemlich viel über die Module, in denen sie erstellt werden.

Ein weiterer Kontrastpunkt ist, dass Zeichenfolgen, die Schlüssel in Wörterbüchern sind, normalerweise interniert werden, damit sie nicht dupliziert werden. Durch das Überprüfen auf id(key)können wir auch vermeiden, dass Duplikate gezählt werden, was wir im nächsten Abschnitt tun. Die Blacklist-Lösung überspringt das Zählen von Schlüsseln, die insgesamt Zeichenfolgen sind.

Whitelisted-Typen, rekursiver Besucher (alte Implementierung)

Um die meisten dieser Typen selbst abzudecken, habe ich diese rekursive Funktion geschrieben, anstatt zu versuchen, die Größe der meisten Python-Objekte zu schätzen, einschließlich der meisten integrierten Funktionen, Typen im Sammlungsmodul und benutzerdefinierter Typen (mit und ohne Slots). .

Diese Art von Funktion bietet eine viel feinere Kontrolle über die Typen, die für die Speichernutzung gezählt werden sollen, birgt jedoch die Gefahr, dass Typen weggelassen werden:

import sys
from numbers import Number
from collections import Set, Mapping, deque

try: # Python 2
    zero_depth_bases = (basestring, Number, xrange, bytearray)
    iteritems = 'iteritems'
except NameError: # Python 3
    zero_depth_bases = (str, bytes, Number, range, bytearray)
    iteritems = 'items'

def getsize(obj_0):
    """Recursively iterate to sum size of object & members."""
    _seen_ids = set()
    def inner(obj):
        obj_id = id(obj)
        if obj_id in _seen_ids:
            return 0
        _seen_ids.add(obj_id)
        size = sys.getsizeof(obj)
        if isinstance(obj, zero_depth_bases):
            pass # bypass remaining control flow and return
        elif isinstance(obj, (tuple, list, Set, deque)):
            size += sum(inner(i) for i in obj)
        elif isinstance(obj, Mapping) or hasattr(obj, iteritems):
            size += sum(inner(k) + inner(v) for k, v in getattr(obj, iteritems)())
        # Check for custom object instances - may subclass above too
        if hasattr(obj, '__dict__'):
            size += inner(vars(obj))
        if hasattr(obj, '__slots__'): # can have __slots__ with __dict__
            size += sum(inner(getattr(obj, s)) for s in obj.__slots__ if hasattr(obj, s))
        return size
    return inner(obj_0)

Und ich habe es eher beiläufig getestet (ich sollte es nicht testen):

>>> getsize(['a', tuple('bcd'), Foo()])
344
>>> getsize(Foo())
16
>>> getsize(tuple('bcd'))
194
>>> getsize(['a', tuple('bcd'), Foo(), {'foo': 'bar', 'baz': 'bar'}])
752
>>> getsize({'foo': 'bar', 'baz': 'bar'})
400
>>> getsize({})
280
>>> getsize({'foo':'bar'})
360
>>> getsize('foo')
40
>>> class Bar():
...     def baz():
...         pass
>>> getsize(Bar())
352
>>> getsize(Bar().__dict__)
280
>>> sys.getsizeof(Bar())
72
>>> getsize(Bar.__dict__)
872
>>> sys.getsizeof(Bar.__dict__)
280

Diese Implementierung gliedert sich in Klassendefinitionen und Funktionsdefinitionen, da wir nicht alle ihre Attribute verfolgen. Da sie jedoch nur einmal im Speicher für den Prozess vorhanden sein sollten, spielt ihre Größe keine große Rolle.

Aaron Hall
quelle
5
Sie könnten hinzufügen, dass diese Antwort spezifisch für CPython ist (was impliziert wird, dass Sie Python über Anaconda erhalten)
gerrit
1
CPython ist die Referenzimplementierung, und ich habe gerade die Online-Dokumente von jython überprüft, die dieselbe API bereitstellen. Daher glaube ich, dass dies bei anderen Implementierungen funktioniert, sofern sie die APIs implementieren.
Aaron Hall
für mich funktionierte nicht für maskierte und nicht maskierte numpy Arrays stackoverflow.com/q/58675479/2132157
GM
95

Das Modul des Pympler- Pakets asizeofkann dies tun.

Verwenden Sie wie folgt:

from pympler import asizeof
asizeof.asizeof(my_object)

Im Gegensatz sys.getsizeofdazu funktioniert es für Ihre selbst erstellten Objekte . Es funktioniert sogar mit Numpy.

>>> asizeof.asizeof(tuple('bcd'))
200
>>> asizeof.asizeof({'foo': 'bar', 'baz': 'bar'})
400
>>> asizeof.asizeof({})
280
>>> asizeof.asizeof({'foo':'bar'})
360
>>> asizeof.asizeof('foo')
40
>>> asizeof.asizeof(Bar())
352
>>> asizeof.asizeof(Bar().__dict__)
280
>>> A = rand(10)
>>> B = rand(10000)
>>> asizeof.asizeof(A)
176
>>> asizeof.asizeof(B)
80096

Wie bereits erwähnt ,

Die (Byte-) Codegröße von Objekten wie Klassen, Funktionen, Methoden, Modulen usw. kann durch Festlegen der Option angegeben werden code=True.

Und wenn Sie eine andere Ansicht von Live-Daten benötigen, Pympler's

Das Modul muppywird zur Online-Überwachung einer Python-Anwendung verwendet und Class Trackerbietet eine Offline-Analyse der Lebensdauer ausgewählter Python-Objekte.

serv-inc
quelle
Diese Funktion ist für größere Objekte ziemlich langsam. Gibt es ein "schnelles" Äquivalent, das für selbst erstellte Objekte funktioniert?
Shuklaswag
Ich habe es noch nicht getestet, org.apache.spark.util.SizeEstimatorkann aber relevant sein
Shuklaswag
1
@ Shuklaswag: Wenn Sie Funken verwenden, könnte es gut sein. Denken Sie, dass die Conversion + Java-Schätzung schneller ist als die in Python integrierten Methoden? Oder habe ich falsch verstanden?
serv-inc
3
Es könnte erwähnenswert sein, dass pympleres Funktionen zur Berücksichtigung der Größe des ausführbaren Codes von Funktionen und anderen aufrufbaren Elementen und Codeobjekten bietet.
mtraceur
Ich erhalte eine TypeErrorAusnahme: "'NoneType'-Objekt ist nicht aufrufbar", wenn mein benutzerdefiniertes Objekt in seinem "Baum" ein Unterobjekt mit Wert enthält None. Gibt es dafür eine schnelle Problemumgehung?
James Hirschorn
81

Bei numpy Arrays getsizeoffunktioniert das nicht - bei mir wird aus irgendeinem Grund immer 40 zurückgegeben:

from pylab import *
from sys import getsizeof
A = rand(10)
B = rand(10000)

Dann (in ipython):

In [64]: getsizeof(A)
Out[64]: 40

In [65]: getsizeof(B)
Out[65]: 40

Zum Glück:

In [66]: A.nbytes
Out[66]: 80

In [67]: B.nbytes
Out[67]: 80000
Mike Dewar
quelle
29
> Alle integrierten Objekte geben korrekte Ergebnisse zurück, dies muss jedoch nicht für Erweiterungen von Drittanbietern gelten, da es implementierungsspezifisch ist. docs.python.org/library/sys.html#sys.getsizeof
warvariuc
33
"Wenn Sie ein Numpy-Array verwenden ( docs.scipy.org/doc/numpy/reference/arrays.ndarray.html ), können Sie das Attribut 'ndarray.nbytes' verwenden, um seine Größe im Speicher zu bewerten." stackoverflow.com/a/15591157/556413
glarrain
17
Ich würde vermuten, dass 40 Bytes korrekt sind, getsizeof()gibt jedoch nur die Größe des Objekts (den Header des Arrays) an, nicht die darin enthaltenen Daten. Gleiches gilt für Python-Container sys.getsizeof([1,2,4]) == sys.getsizeof([1,123**456,4]) == 48, bei denensys.getsizeof(123**456) = 436
yota
3
Es scheint, dass die getsizeof()Funktion irgendwann geändert wurde, um den erwarteten Wert zurückzugeben.
Dshin
14

Dies kann komplizierter sein, als es aussieht, je nachdem, wie Sie die Dinge zählen möchten. Wenn Sie beispielsweise eine Liste von Ints haben, möchten Sie die Größe der Liste, die die Verweise auf die Ints enthält? (dh nur eine Liste, nicht das, was darin enthalten ist), oder möchten Sie die tatsächlichen Daten einschließen, auf die verwiesen wird? In diesem Fall müssen Sie sich mit doppelten Referenzen befassen und wie Sie eine Doppelzählung verhindern, wenn zwei Objekte Verweise auf enthalten das gleiche Objekt.

Vielleicht möchten Sie einen Blick auf einen der Python-Speicherprofiler werfen , z. B. Pysizer , um festzustellen , ob diese Ihren Anforderungen entsprechen.

Brian
quelle
14

Python 3.8 (Q1 2019) wird einige der Ergebnisse von ändern sys.getsizeof, wie hier von Raymond Hettinger angekündigt :

Python-Container sind bei 64-Bit-Builds 8 Byte kleiner.

tuple ()  48 -> 40       
list  []  64 ->56
set()    224 -> 216
dict  {} 240 -> 232

Dies geschieht nach Ausgabe 33597 und Inada Naokis ( methane) Arbeit um Compact PyGC_Head und PR 7043

Diese Idee reduziert die Größe von PyGC_Head auf zwei Wörter .

Derzeit benötigt PyGC_Head drei Wörter . gc_prev, gc_nextUnd gc_refcnt.

  • gc_refcnt wird beim Sammeln zum Löschen der Testversion verwendet.
  • gc_prev wird zum Verfolgen und Aufspüren verwendet.

Wenn wir also das Verfolgen / Aufspüren während des Löschens der Testversion vermeiden gc_prevund gc_refcntdenselben Speicherplatz gemeinsam nutzen können.

Siehe Commit d5c875b :

Ein Py_ssize_tMitglied wurde entfernt von PyGC_Head.
Die Größe aller GC-verfolgten Objekte (z. B. Tupel, Liste, Diktat) wird um 4 oder 8 Byte reduziert.

VonC
quelle
10

Nachdem ich selbst oft auf dieses Problem gestoßen war, schrieb ich eine kleine Funktion (inspiriert von der Antwort von @ aaron-hall) und Tests, die das tun, was ich von sys.getsizeof erwartet hätte:

https://github.com/bosswissam/pysize

Wenn Sie an der Hintergrundgeschichte interessiert sind, hier ist sie

BEARBEITEN: Fügen Sie den folgenden Code zur leichteren Bezugnahme hinzu. Um den aktuellsten Code zu sehen, überprüfen Sie bitte den Github-Link.

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

Hier ist ein kurzes Skript, das ich basierend auf den vorherigen Antworten auf die Listengrößen aller Variablen geschrieben habe

for i in dir():
    print (i, sys.getsizeof(eval(i)) )
alexey
quelle
Es ist nicht falsch, es ist mehrdeutig. sys.getsizeof gibt immer den Wert zurück, der benötigt wird, sodass bei try..except keine Leistungseinbußen erforderlich sind.
der_fenix
Oh, das ist ein guter Punkt, und ich habe nicht darüber nachgedacht - der Code in der aktuellen Form zeigt nur, wie er chronologisch geschrieben wurde - zuerst wusste ich über Numpy (daher Nbytes) Bescheid, dann suchte ich nach einer allgemeineren Lösung . Vielen Dank für die Erklärung _ / \ _
Alexey
7

Sie können das Objekt serialisieren, um ein Maß abzuleiten, das eng mit der Größe des Objekts zusammenhängt:

import pickle

## let o be the object, whose size you want to measure
size_estimate = len(pickle.dumps(o))

Wenn Sie Objekte messen möchten, die nicht eingelegt werden können (z. B. aufgrund von Lambda-Ausdrücken), kann Cloudpickle eine Lösung sein.

Jemand
quelle
4

Verwenden Sie sys.getsizeof (), wenn Sie die Größe verknüpfter (verschachtelter) Objekte NICHT einschließen möchten.

Wenn Sie jedoch Unterobjekte zählen möchten, die in Listen, Diktaten, Mengen, Tupeln verschachtelt sind - und normalerweise ist dies das, wonach Sie suchen -, verwenden Sie die rekursive Funktion deep sizeof () wie folgt :

import sys
def sizeof(obj):
    size = sys.getsizeof(obj)
    if isinstance(obj, dict): return size + sum(map(sizeof, obj.keys())) + sum(map(sizeof, obj.values()))
    if isinstance(obj, (list, tuple, set, frozenset)): return size + sum(map(sizeof, obj))
    return size

Sie finden diese Funktion zusammen mit vielen anderen nützlichen Einzeilern auch in der raffinierten Toolbox:

https://github.com/mwojnars/nifty/blob/master/util.py

Marcin Wojnarski
quelle
3

Wenn Sie nicht die genaue Größe des Objekts benötigen, aber ungefähr wissen möchten, wie groß es ist, können Sie das Programm schnell (und schmutzig) laufen lassen, über einen längeren Zeitraum in den Ruhezustand versetzen und die Speichernutzung überprüfen (z : Macs Aktivitätsmonitor) durch diesen speziellen Python-Prozess. Dies ist effektiv, wenn Sie versuchen, die Größe eines einzelnen großen Objekts in einem Python-Prozess zu ermitteln. Zum Beispiel wollte ich kürzlich die Speichernutzung einer neuen Datenstruktur überprüfen und mit der von Pythons festgelegter Datenstruktur vergleichen. Zuerst schrieb ich die Elemente (Wörter aus einem großen gemeinfreien Buch) in eine Menge, überprüfte dann die Größe des Prozesses und tat dann dasselbe mit der anderen Datenstruktur. Ich habe herausgefunden, dass der Python-Prozess mit einem Satz doppelt so viel Speicher benötigt wie die neue Datenstruktur. Wieder würden Sie nicht ' Ich kann nicht genau sagen, dass der vom Prozess verwendete Speicher der Größe des Objekts entspricht. Wenn die Größe des Objekts groß wird, wird dies eng, da der vom Rest des Prozesses verbrauchte Speicher im Vergleich zur Größe des Objekts, das Sie überwachen möchten, vernachlässigbar wird.

picmate 涅
quelle
1
Die Frage lautet, wie dies in Python gemacht werden soll , nicht nur die Speichernutzung von Python-Objekten zu ermitteln und die Verwendung des Aktivitätsmonitors eines Mac oder einer ähnlichen Software nicht programmgesteuert mit Python. Abgesehen davon ist die Überprüfung der Speichernutzung von Python-Prozessen auf diese Weise im Allgemeinen ein guter Weg, um sicherzustellen, dass nichts schief gelaufen ist ...
Tom Wyllie
@ TomWyllie, danke, aber das Herunterstimmen dieser Antwort hat die negative Konnotation, dass die Antwort selbst falsch ist und nichts bewirkt. Die von mir erwähnte Methode ist möglicherweise nicht in Python implementiert, aber es ist eine praktische Möglichkeit, eine grobe Schätzung der Größe eines Python-Objekts zu erhalten. Ich wusste, dass ich die genaue Frage nicht beantworte, aber die Methode könnte für jemand anderen nützlich sein, um ein ähnliches Ergebnis zu erzielen.
Picmate 涅
1

Sie können getSizeof () wie unten erwähnt verwenden, um die Größe eines Objekts zu bestimmen

import sys
str1 = "one"
int_element=5
print("Memory size of '"+str1+"' = "+str(sys.getsizeof(str1))+ " bytes")
print("Memory size of '"+ str(int_element)+"' = "+str(sys.getsizeof(int_element))+ " bytes")
Forkdbloke
quelle
0

Ich benutze diesen Trick ... Kann bei kleinen Objekten nicht genau sein, aber ich denke, es ist viel genauer für ein komplexes Objekt (wie eine Pygame-Oberfläche) als für sys.getsizeof ()

import pygame as pg
import os
import psutil
import time


process = psutil.Process(os.getpid())
pg.init()    
vocab = ['hello', 'me', 'you', 'she', 'he', 'they', 'we',
         'should', 'why?', 'necessarily', 'do', 'that']

font = pg.font.SysFont("monospace", 100, True)

dct = {}

newMem = process.memory_info().rss  # don't mind this line
Str = f'store ' + f'Nothing \tsurface use about '.expandtabs(15) + \
      f'0\t bytes'.expandtabs(9)  # don't mind this assignment too

usedMem = process.memory_info().rss

for word in vocab:
    dct[word] = font.render(word, True, pg.Color("#000000"))

    time.sleep(0.1)  # wait a moment

    # get total used memory of this script:
    newMem = process.memory_info().rss
    Str = f'store ' + f'{word}\tsurface use about '.expandtabs(15) + \
          f'{newMem - usedMem}\t bytes'.expandtabs(9)

    print(Str)
    usedMem = newMem

Unter Windows 10, Python 3.7.3, lautet die Ausgabe:

store hello          surface use about 225280    bytes
store me             surface use about 61440     bytes
store you            surface use about 94208     bytes
store she            surface use about 81920     bytes
store he             surface use about 53248     bytes
store they           surface use about 114688    bytes
store we             surface use about 57344     bytes
store should         surface use about 172032    bytes
store why?           surface use about 110592    bytes
store necessarily    surface use about 311296    bytes
store do             surface use about 57344     bytes
store that           surface use about 110592    bytes
Hzzkygcs
quelle