Размер в памяти структуры Python

118

Есть ли ссылка на размер памяти структуры данных Python на 32- и 64-битных платформах?

Если нет, было бы неплохо иметь его на SO. Чем полнее, тем лучше! Итак, сколько байтов используется следующими структурами Python (в зависимости от lenтипа содержимого и, если это необходимо)?

  • int
  • float
  • ссылка
  • str
  • строка Юникода
  • tuple
  • list
  • dict
  • set
  • array.array
  • numpy.array
  • deque
  • объект классов нового стиля
  • объект классов в старом стиле
  • ... и все, что я забываю!

(Для контейнеров, которые хранят только ссылки на другие объекты, мы, очевидно, не хотим подсчитывать размер самого элемента, поскольку он может быть общим.)

Кроме того, есть ли способ получить память, используемую объектом во время выполнения (рекурсивно или нет)?

LeMiz
источник
Здесь можно найти множество полезных объяснений stackoverflow.com/questions/1059674/python-memory-model . Я бы хотел увидеть более систематический обзор
LeMiz
3
Для массива NumPy aиспользуйте a.nbytes.
Уилл
Если вас интересует графическое представление этого, я однажды
нарисовал его график

Ответы:

145

Рекомендация из более раннего вопроса по этому поводу заключалась в использовании sys.getsizeof () , цитируя:

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

Вы можете использовать такой подход:

>>> 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-разрядная версия):

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-разрядная версия)

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 (по умолчанию, 23 октября 2015 г., 19:19:21) [Apple LLVM 7.0.0, совместимый с GCC 4.2.1 (clang-700.0.59.5)] на darwin

decimal 80
dict 280
float 24
int 24
list 72
object 16
set 232
str 38
tuple 56
unicode 52
hughdbrown
источник
1
Спасибо и извините за обман по второму вопросу ... очень плохо, я использую 2.5, а не 2.6 ...
LeMiz
Я забыл, что у меня есть виртуальный ящик с последней версией Ubuntu! Странно, sys.getsizeof (dict) для меня - 136 (python 2.6 работает на kubuntu vm, размещенном на OS X, поэтому я ни в чем не уверен)
LeMiz
@LeMiz: Для меня (Python 2.6, Windows XP SP3) sys.getsizeof (dict) -> 436; sys.getsizeof (dict ()) -> 140
Джон Мачин
LeMiz-Kubuntu: python2.6 Python 2.6.2 (release26-maint, 19 апреля 2009 г., 01:56:41) [GCC 4.3.3] в linux2 Введите "help", "copyright", "credits" или "license" Чтобы получить больше информации. >>> import sys >>> sys.getsizeof (dict) 436 >>> sys.getsizeof (dict ()) 136
ЛеМиз
1
не должно быть значения 0, 0.0, ''и u''для последовательности?
SilentGhost
37

Я с удовольствием использую pympler для таких задач. Он совместим со многими версиями Python - asizeofв частности, этот модуль восходит к 2.2!

Например, используя пример hughdbrown, но с from pympler import asizeofв начале и print asizeof.asizeof(v)в конце, я вижу (система Python 2.5 на 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

Ясно, что здесь есть некоторое приближение, но я нашел его очень полезным для анализа и настройки посадочного места.

Алекс Мартелли
источник
1
Некоторые любопытства: у большинства из вас числа на 4 выше; объект 0; а десятичное число примерно в 4 раза больше по вашей оценке.
hughdbrown
1
Ага. «4 выше» на самом деле в основном выглядит как «округление до кратного 8», что я считаю правильным для поведения malloc. Понятия не имею, почему десятичная дробь так искажается (с pympler на 2.6 тоже).
Alex Martelli
2
Фактически, вы должны использовать pympler.asizeof.flatsize (), чтобы получить функциональность, аналогичную sys.getsizeof (). Существует также параметр align =, который вы можете использовать (который по умолчанию равен 8, как указал Алекс).
Панкрат,
@AlexMartelli Привет, Алекс! .. Почему минимальный размер символа в python составляет 25 байт. >>> getsizeof('a')дает 25и >>> getsizeof('ab')дает 26`
Grijesh Chauhan
1
Я полагаю, размер указан в байтах, но почему он нигде не написан, даже в pythonhosted.org/Pympler
Жомарт
35

Все эти ответы собирают информацию о мелких размерах. Я подозреваю, что посетители этого вопроса в конечном итоге будут здесь пытаться ответить на вопрос: «Насколько велик этот сложный объект в памяти?»

Здесь есть отличный ответ: https://goshippo.com/blog/measure-real-size-any-python-object/

Изюминка:

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

Используется так:

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

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

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

Если вы хотите более глубоко изучить модель памяти Python, есть отличная статья, в которой есть аналогичный фрагмент кода «общего размера» как часть более подробного объяснения: https://code.tutsplus.com/tutorials/understand-how- много-памяти-ваш-питон-объекты использования - CMS-25609

Kobold
источник
Итак, это должно дать общий объем памяти, используемый, например, dict, содержащим несколько массивов и / или других dicts?
Charly Empereur-mot
1
@ CharlyEmpereur-mot, ага.
Кобольд
Отличный ответ. Однако, похоже, это не работает для скомпилированных объектов cython. В моем случае этот метод возвращает 96указатель на объект
cython
8

Попробуйте профайлер памяти. профайлер памяти

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
источник
1
Точность составляет 1/100 МБ или 10,24 байта. Это хорошо для макроанализа, но я сомневаюсь, что такая точность приведет к точному сравнению структур данных, как задано в вопросе.
Зоран Павлович
7

Также вы можете использовать модуль гуппи .

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

И:

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

Также можно использовать tracemallocмодуль из стандартной библиотеки Python. Кажется, он хорошо работает для объектов, класс которых реализован на C (например, в отличие от Pympler).

zahypeti
источник
-1

Когда вы используете dir([object])встроенную функцию, вы можете получить __sizeof__ее встроенную функцию.

>>> a = -1
>>> a.__sizeof__()
24
hello_god
источник