Tamanho na memória de uma estrutura Python

118

Existe uma referência para o tamanho da memória da estrutura de dados Python em plataformas de 32 e 64 bits?

Se não, seria bom tê-lo no SO. Quanto mais exaustivo, melhor! Então, quantos bytes são usados ​​pelas seguintes estruturas Python (dependendo do lene do tipo de conteúdo quando relevante)?

  • int
  • float
  • referência
  • str
  • string unicode
  • tuple
  • list
  • dict
  • set
  • array.array
  • numpy.array
  • deque
  • objeto de classes de novo estilo
  • objeto de classes de estilo antigo
  • ... e tudo que estou esquecendo!

(Para contêineres que mantêm apenas referências a outros objetos, obviamente não queremos contar o tamanho do item em si, uma vez que ele pode ser compartilhado.)

Além disso, existe uma maneira de obter a memória usada por um objeto em tempo de execução (recursivamente ou não)?

LeMiz
fonte
Muitas explicações úteis podem ser encontradas aqui stackoverflow.com/questions/1059674/python-memory-model . Eu gostaria de ver uma visão geral mais sistemática, no entanto
LeMiz
3
Para uma matriz NumPy a, use a.nbytes.
Será
Se você estiver interessado em uma visualização gráfica disso, fiz um gráfico uma vez: stackoverflow.com/a/30008338/2087463
tmthydvnprt

Respostas:

145

A recomendação de uma pergunta anterior sobre isso era usar sys.getsizeof () , citando:

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

Você pode adotar esta abordagem:

>>> 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 (padrão, 23 de outubro de 2015, 19:19:21) [GCC 4.2.1 compatível com Apple LLVM 7.0.0 (clang-700.0.59.5)] em darwin

decimal 80
dict 280
float 24
int 24
list 72
object 16
set 232
str 38
tuple 56
unicode 52
Hughdbrown
fonte
1
Obrigado e desculpem pelo tolo da segunda pergunta ... que pena que estou usando 2.5 e não 2.6 ...
LeMiz
Esqueci que tinha uma caixa virtual com um ubuntu recente! Isso é estranho, sys.getsizeof (dict) é 136 para mim (python 2.6 rodando em um kubuntu vm, hospedado pelo OS X, então não tenho certeza de nada)
LeMiz
@LeMiz: Para mim (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, abr 19 2009, 01:56:41) [GCC 4.3.3] no linux2 Digite "help", "copyright", "credits" ou "license" Para maiores informações. >>> import sys >>> sys.getsizeof (dict) 436 >>> sys.getsizeof (dict ()) 136
LeMiz
1
Não devem os valores ser 0, 0.0, ''e u''para a consistência?
SilentGhost
37

Estou feliz usando pympler para essas tarefas. É compatível com muitas versões do Python - oasizeof módulo em particular remonta ao 2.2!

Por exemplo, usando o exemplo de hughdbrown, mas com from pympler import asizeofno início e print asizeof.asizeof(v)no final, vejo (sistema Python 2.5 no 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

É claro que há alguma aproximação aqui, mas eu achei muito útil para análise e ajuste de footprint.

Alex Martelli
fonte
1
Algumas curiosidades: a maioria de seus números é 4 a mais; o objeto é 0; e decimal é cerca de 4 vezes maior pela sua estimativa.
hughdbrown
1
Sim. O "4 mais alto" na verdade se parece principalmente com "arredondando para um múltiplo de 8", o que acredito ser correto para a forma como o malloc se comporta aqui. Não faço ideia por que o decimal fica tão distorcido (com pympler no 2.6 também).
Alex Martelli
2
Na verdade, você deve usar pympler.asizeof.flatsize () para obter uma funcionalidade semelhante a sys.getsizeof (). Há também um parâmetro align = que você pode usar (que é 8 por padrão, como Alex apontou).
Pankrat
@AlexMartelli Oi Alex! .. Por que o tamanho mínimo de um char em python é 25 bytes. >>> getsizeof('a')25e >>> getsizeof('ab')26`
Grijesh Chauhan
1
Suponho que o tamanho está em bytes, mas por que não está escrito em nenhum lugar, mesmo em pythonhosted.org/Pympler
Zhomart
35

Todas essas respostas coletam informações de tamanho superficial. Suspeito que os visitantes desta pergunta acabarão aqui procurando responder à pergunta: "Qual o tamanho deste objeto complexo na memória?"

Há uma ótima resposta aqui: https://goshippo.com/blog/measure-real-size-any-python-object/

A piada:

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

Usado assim:

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

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

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

Se você quiser conhecer o modelo de memória do Python mais profundamente, há um ótimo artigo aqui que tem um trecho de código de "tamanho total" semelhante como parte de uma explicação mais longa: https://code.tutsplus.com/tutorials/understand-how- much-memory-your-python-objects-use - cms-25609

Kobold
fonte
Portanto, isso deve render a quantidade total de memória usada por, por exemplo, um dicionário contendo vários vetores e / ou outros dicts?
Charly Empereur-mot
1
@ CharlyEmpereur-mot sim.
Kobold de
Ótima resposta. No entanto, não parece funcionar para objetos de cíton compilados. No meu caso, esse método retorna 96para um ponteiro para um objeto cíton na memória
ferdynator
8

Experimente o criador de perfil de memória. perfilador de memória

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
fonte
1
A precisão parece ser 1/100 MB ou 10,24 bytes. Isso é bom para a macroanálise, mas duvido que tal precisão leve a uma comparação precisa das estruturas de dados, conforme perguntado na pergunta.
Zoran Pavlovic
7

Você também pode usar o módulo 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.>

E:

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

Também é possível usar o tracemallocmódulo da biblioteca padrão Python. Parece funcionar bem para objetos cuja classe é implementada em C (ao contrário de Pympler, por exemplo).

zahypeti
fonte
-1

Ao usar a dir([object])função integrada, você pode obter o __sizeof__da função integrada.

>>> a = -1
>>> a.__sizeof__()
24
hello_god
fonte