2008-09-25 14 views
13

Por ejemplo, ¿cuánta memoria se requiere para almacenar una lista de enteros de un millón (32 bits)?¿Cuántos bytes por elemento hay en una lista de Python (tupla)?

alist = range(1000000) # or list(range(1000000)) in Python 3.0 
+0

Pruébelo? Ejemplo gráfico que hice: http://stackoverflow.com/a/30008338/2087463 – tmthydvnprt

+0

@tmthydvnprt: su respuesta se basa únicamente en una llamada 'sys.getsizeof()' que es incorrecta. Compare los resultados con ['asizeof.asizeof()' de mi respuesta] (http://stackoverflow.com/a/136083/4279) (p. Ej., En mi sistema: 'sys.getsizeof (rango (10 ** 6)) '->' 8000072' mientras 'asizeof.asizeof (rango (10 ** 6))' -> '32000072'). – jfs

+0

¿por qué un único 'sys.getsizeof()' es incorrecto? – tmthydvnprt

Respuesta

13

Enlaces de interés:

How to get memory size/usage of python object

Memory sizes of python objects?

if you put data into dictionary, how do we calculate the data size?

Sin embargo no dan una respuesta definitiva. El camino a seguir: la memoria

  1. Medida consumida por intérprete de Python con/sin la lista (herramientas de uso del sistema operativo).

  2. Utilice un módulo de extensión de terceros que defina algún tipo de tamaño de (PyObject).

actualización:

Recipe 546530: Size of Python objects (revised)

import asizeof 

N = 1000000 
print asizeof.asizeof(range(N))/N 
# -> 20 (python 2.5, WinXP, 32-bit Linux) 
# -> 33 (64-bit Linux) 
+0

¿Puedo usar sys.getsizeof() para obtener el tamaño de una lista? – Alcott

+1

@Alcott: El módulo 'asizeof' usa' sys.getsizeof' cuando está disponible y es aplicable. – jfs

+0

bueno, asizeof es un material de terceros, ¿no? – Alcott

23

"It depends." Python asigna espacio para las listas de manera que se logre amortized constant time para agregar elementos a la lista.

En la práctica, lo que esto significa con la implementación actual es ... la lista siempre tiene espacio asignado para una cantidad de elementos de potencia de dos. Entonces, el rango (1000000) realmente asignará una lista lo suficientemente grande como para contener 2^20 elementos (~ 1.045 millones).

Este es solo el espacio requerido para almacenar la estructura de la lista en sí (que es una matriz de punteros a los objetos de Python para cada elemento). Un sistema de 32 bits requerirá 4 bytes por elemento, un sistema de 64 bits usará 8 bytes por elemento.

Además, necesita espacio para almacenar los elementos reales. Esto varía ampliamente. Para enteros pequeños (de -5 a 256 actualmente), no se necesita espacio adicional, pero para números más grandes Python asigna un nuevo objeto para cada entero, que toma de 10 a 100 bytes y tiende a fragmentar la memoria.

En pocas palabras: es complicado y Python listas son no una buena manera de almacenar grandes estructuras de datos homogéneos. Para eso, use el módulo array o, si necesita hacer cálculos vectorizados, use NumPy.

PS-Tuplas, a diferencia de las listas, son no diseñadas para tener elementos progresivamente añadidos a ellas. No sé cómo funciona el asignador, pero ni siquiera pienso en utilizarlo para estructuras de datos de gran tamaño :-)

+1

Las tuplas no solo no están diseñadas para agregarse como adjuntas, no * pueden agregarse.El análogo más cercano implica crear una nueva tupla por completo (y luego posiblemente destruir la antigua) que es muy ineficiente. –

+0

Sí de hecho. Creo que lo que estaba obteniendo es ... no solo Python no permite agregar a tuplas, sino que internamente la memoria para ellos no se gestiona de manera tal que sea eficiente. –

+6

Nitpick: no es un factor de crecimiento de poder de dos. Se sobreatribuye por tamaño/8, más 6 (o 3 si es <= 8 elementos). Es proporcional al tamaño, por lo que seguirá dando una constante amortiguada, pero solo usa ~ 12.5% ​​de espacio adicional. Ver listobject.c para la implementación. – Brian

2

Esto es específico de la implementación, estoy bastante seguro. Ciertamente, depende de la representación interna de los enteros: no se puede suponer que se almacenarán en 32 bits, ya que Python te proporciona enteros arbitrariamente grandes, por lo que quizás los pequeños enteros se almacenen de forma más compacta.

En mi Python (2.5.1 en Fedora 9 en core 2 duo) el VmSize antes de la asignación es 6896kB, después es 22684kB. Después de una asignación de elemento de más de un millón, VmSize va a 38340kB. Esto indica groseramente alrededor de 16000kB para 1000000 enteros, que es alrededor de 16 bytes por entero. Eso sugiere un lote de sobrecarga para la lista. Tomaría estos números con una gran pizca de sal.

6

Direccionamiento "tupla" parte de la pregunta

Declaración de PyTuple de CPython en una configuración típica de construcción se reduce a esto :

struct PyTuple { 
    size_t refcount; // tuple's reference count 
    typeobject *type; // tuple type object 
    size_t n_items; // number of items in tuple 
    PyObject *items[1]; // contains space for n_items elements 
}; 

El tamaño de la instancia de PyTuple se repara durante su construcción y no se puede cambiar después. El número de bytes ocupados por PyTuple se puede calcular como

sizeof(size_t) x 2 + sizeof(void*) x (n_items + 1).

Esto da superficial tamaño de la tupla. Para obtener tamaño completo de, también necesita agregar el número total de bytes consumidos por el gráfico de objetos rooteado en PyTuple::items[] matriz.

Vale la pena señalar que las rutinas de construcción de tuplas se aseguran de que solo se cree una sola instancia de tupla vacía (singleton).

Referencias: Python.h, object.h, tupleobject.h, tupleobject.c

+1

No es tan simple, por ejemplo,'() 32', '(1,) 48',' (1, 2) 72', '(1, 2, 3) 88' - tamaños que incluyen tamaños de elementos ('16' para enteros). – jfs

+1

Se agregó una nota "poco profunda frente a la de tamaño completo". – Constantin

3

una nueva función, getsizeof(), toma un objeto Python y devuelve la cantidad de memoria utilizada por el objeto, medida en bytes . Los objetos incorporados devuelven resultados correctos; las extensiones de terceros no pueden, pero pueden definir un método __sizeof__() para devolver el tamaño del objeto.

[email protected]:~/py/r26rc2$ ./python 
Python 2.6rc2 (r26rc2:66712, Sep 2 2008, 13:11:55) 
[GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)] on linux2 
>>> import sys 
>>> sys.getsizeof(range(1000000)) 
4000032 
>>> sys.getsizeof(tuple(range(1000000))) 
4000024 

Obviamente regresaron números no incluyen memoria consumida por los objetos contenidos (sys.getsizeof (1) == 12).

+0

El módulo 'asizeof' usa' sys.getsizeof' cuando está disponible y es aplicable. Ver mi respuesta – jfs

-1

Soy cauteloso de por qué lo preguntas. ¿Estás tratando de calcular cuánta memoria necesitarás para una implementación determinada? Digamos que vas a leer 10,000,000 widgets y quieres saber cuánta RAM chupará.

Si ese es el caso, en lugar de tratar de calcular cuánta RAM toma cada widget, averigüe cuánta RAM, digamos, 10.000 widgets toma y multiplique para obtener su tamaño real.

+2

La aplicación principal es cálculos de respaldo para tener una idea general de cuándo y dónde Python es la herramienta adecuada para un trabajo. – jfs

Cuestiones relacionadas