Rozmiar struktury Pythona w pamięci

118

Czy istnieje odniesienie do rozmiaru pamięci struktury danych Pythona na platformach 32- i 64-bitowych?

Jeśli nie, byłoby miło mieć go na SO. Im bardziej wyczerpujący, tym lepiej! Ile bajtów jest używanych przez następujące struktury Pythona (w zależności od lentypu zawartości i, jeśli ma to zastosowanie)?

  • int
  • float
  • odniesienie
  • str
  • ciąg znaków Unicode
  • tuple
  • list
  • dict
  • set
  • array.array
  • numpy.array
  • deque
  • obiekt klas w nowym stylu
  • obiekt klas w starym stylu
  • ... i wszystko, o czym zapominam!

(W przypadku kontenerów, które przechowują tylko odniesienia do innych obiektów, oczywiście nie chcemy liczyć samego rozmiaru elementu, ponieważ może on być udostępniany).

Ponadto, czy istnieje sposób na uzyskanie pamięci używanej przez obiekt w czasie wykonywania (rekurencyjnie lub nie)?

LeMiz
źródło
Wiele pomocnych wyjaśnień można znaleźć tutaj stackoverflow.com/questions/1059674/python-memory-model . Chciałbym jednak zobaczyć bardziej systematyczny przegląd
LeMiz
3
W przypadku tablicy NumPy aużyj a.nbytes.
Will
Jeśli jesteście zainteresowani graficznym widokiem tego, zrobiłem kiedyś jego wykres: stackoverflow.com/a/30008338/2087463
tmthydvnprt

Odpowiedzi:

145

Zaleceniem z wcześniejszego pytania było użycie sys.getsizeof () , cytując:

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

Możesz przyjąć takie podejście:

>>> 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-bitowy):

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

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 (domyślnie, 23 października 2015, 19:19:21) [Zgodny z GCC 4.2.1 Apple LLVM 7.0.0 (clang-700.0.59.5)] na darwin

decimal 80
dict 280
float 24
int 24
list 72
object 16
set 232
str 38
tuple 56
unicode 52
hughdbrown
źródło
1
Dziękuję i przepraszam za dupe na drugie pytanie ... szkoda, używam 2.5 a nie 2.6 ...
LeMiz
Zapomniałem, że mam wirtualne pudełko z niedawnym ubuntu! To dziwne, sys.getsizeof (dict) to dla mnie 136 (python 2.6 działający na maszynie wirtualnej kubuntu, hostowanej przez OS X, więc niczego nie jestem pewien)
LeMiz
@LeMiz: Dla mnie (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 kwietnia 2009, 01:56:41) [GCC 4.3.3] na linux2 Wpisz „pomoc”, „prawa autorskie”, „kredyty” lub „licencja” po więcej informacji. >>> import sys >>> sys.getsizeof (dict) 436 >>> sys.getsizeof (dict ()) 136
LeMiz
1
nie powinny być wartości 0, 0.0, ''i u''dla spójności?
SilentGhost
37

Z radością używam pymplera do takich zadań. Jest kompatybilny z wieloma wersjami Pythona - asizeofw szczególności moduł wraca do 2.2!

Na przykład, używając przykładu hughdbrown, ale from pympler import asizeofna początku i print asizeof.asizeof(v)na końcu widzę (system Python 2.5 na 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

Oczywiście jest tu pewne przybliżenie, ale uznałem je za bardzo przydatne do analizy i dostrajania śladu.

Alex Martelli
źródło
1
Kilka ciekawostek: większość z was ma 4 wyższe liczby; obiekt to 0; a liczba dziesiętna jest około 4 razy większa według szacunków.
hughdbrown
1
Tak. „4 wyższe” w rzeczywistości zazwyczaj wygląda jak „zaokrąglanie w górę do wielokrotności 8”, co moim zdaniem jest poprawne dla sposobu, w jaki zachowuje się malloc. Nie mam pojęcia, dlaczego liczba dziesiętna jest tak zniekształcona (również z pymplerem na 2.6).
Alex Martelli
2
Właściwie powinieneś użyć pympler.asizeof.flatsize (), aby uzyskać podobną funkcjonalność do sys.getsizeof (). Istnieje również parametr align =, którego możesz użyć (domyślnie 8, jak wskazał Alex).
Pankrat
@AlexMartelli Cześć Alex! .. Dlaczego minimalny rozmiar znaku w Pythonie to 25 bajtów. >>> getsizeof('a')daje 25i >>> getsizeof('ab')daje 26`
Grijesh Chauhan
1
Przypuszczam, że rozmiar jest w bajtach, ale dlaczego nie jest nigdzie zapisany, nawet w pythonhosted.org/Pympler
Zhomart
35

Wszystkie te odpowiedzi zbierają informacje o niewielkich rozmiarach. Podejrzewam, że odwiedzający to pytanie skończą tutaj, szukając odpowiedzi na pytanie: „Jak duży jest ten złożony obiekt w pamięci?”

Tutaj jest świetna odpowiedź: https://goshippo.com/blog/measure-real-size-any-python-object/

Puenta:

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

Używane tak:

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

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

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

Jeśli chcesz dokładniej poznać model pamięci w Pythonie, znajdziesz tutaj świetny artykuł, który zawiera podobny fragment kodu „całkowity rozmiar” jako część dłuższego wyjaśnienia: https://code.tutsplus.com/tutorials/understand-how- dużo-memory-your-python-objects-use - cms-25609

Kobold
źródło
Więc to powinno dać całkowitą ilość pamięci używanej na przykład przez dyktę zawierającą wiele tablic i / lub inne dykty?
Charly Empereur-mot
1
@ CharlyEmpereur-mot tak.
Kobold
Świetna odpowiedź. Wydaje się jednak, że nie działa dla skompilowanych obiektów cython. W moim przypadku ta metoda zwraca 96na wskaźnik do obiektu Cython w pamięci
ferdynator
8

Wypróbuj profiler pamięci. profiler pamięci

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
źródło
1
Precyzja wydaje się wynosić 1/100 MB lub 10,24 bajtów. Jest to w porządku w przypadku analizy makro, ale wątpię, czy taka precyzja prowadziłaby do dokładnego porównania struktur danych zadanych w pytaniu.
Zoran Pavlovic
7

Możesz także użyć modułu 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.>

I:

>>> 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
źródło
0

Można również skorzystać z tracemallocmodułu ze standardowej biblioteki Pythona. Wydaje się, że działa dobrze dla obiektów, których klasa jest zaimplementowana w C (w przeciwieństwie na przykład do Pymplera).

zahypeti
źródło
-1

Korzystając z funkcji dir([object])wbudowanej, można uzyskać dostęp do __sizeof__funkcji wbudowanej.

>>> a = -1
>>> a.__sizeof__()
24
hello_god
źródło