varios variable valor una resultados por nombre mostrar listas lista leer imprimir eliminar elementos consola como cambiar cadena python object memory int python-internals

variable - lista de listas python



¿Por qué los ints requieren tres veces más memoria en Python? (2)

Desde longintrepr.h, vemos que un objeto Python ''int'' se define con esta estructura C:

struct _longobject { PyObject_VAR_HEAD digit ob_digit[1]; };

Digit es un valor sin signo de 32 bits. La mayor parte del espacio está ocupado por el encabezado de objeto de tamaño variable. Desde object.h, podemos encontrar su definición:

typedef struct { PyObject ob_base; Py_ssize_t ob_size; /* Number of items in variable part */ } PyVarObject; typedef struct _object { _PyObject_HEAD_EXTRA Py_ssize_t ob_refcnt; struct _typeobject *ob_type; } PyObject;

Podemos ver que estamos usando un Py_ssize_t, 64 bits, asumiendo un sistema de 64 bits, para almacenar el recuento de "dígitos" en el valor. Esto es posiblemente un desperdicio. También podemos ver que el encabezado general del objeto tiene un recuento de referencias de 64 bits y un puntero al tipo de objeto, que también será de 64 bits de almacenamiento. El recuento de referencias es necesario para que Python sepa cuándo desasignar el objeto, y el puntero al tipo de objeto es necesario para saber que tenemos un int y no, por ejemplo, una cadena, ya que las estructuras C no tienen forma de probar el tipo de un objeto desde un puntero arbitrario.

_PyObject_HEAD_EXTRA está definido como nada en la mayoría de las compilaciones de python, pero se puede usar para almacenar una lista vinculada de todos los objetos de Python en el montón si la compilación habilita esa opción, usando otros dos punteros de 64 bits cada uno.

En un sistema de 64 bits, un entero en Python toma 24 bytes. Esto es 3 veces la memoria que se necesitaría, por ejemplo, C para un entero de 64 bits. Ahora, sé que esto se debe a que los enteros de Python son objetos. Pero, ¿para qué se usa la memoria extra? Tengo mis conjeturas, pero sería bueno saberlo con certeza.


Recuerde que el tipo int Python no tiene un rango limitado como C int tiene; el único límite es la memoria disponible.

La memoria sirve para almacenar el valor, el tamaño actual del almacenamiento entero (el tamaño de almacenamiento es variable para admitir tamaños arbitrarios) y la contabilidad de objetos estándar de Python (una referencia al objeto relevante y un recuento de referencia).

Puede buscar la fuente longintrepr.h (el tipo int Python 3 era tradicionalmente conocido como el tipo long en Python 2); hace un uso efectivo del tipo PyVarObject C para rastrear el tamaño entero:

struct _longobject { PyObject_VAR_HEAD digit ob_digit[1]; };

La matriz ob_digit almacena ''dígitos'' de 15 o 30 bits de ancho (dependiendo de su plataforma); así que en mi sistema OS X de 64 bits, un número entero hasta (2 ^ 30) - 1 usa 1 ''dígito'':

>>> sys.getsizeof((1 << 30) - 1) 28

pero si usa 2 dígitos de 30 bits en el número, se necesitan 4 bytes adicionales, etc.

>>> sys.getsizeof(1 << 30) 32 >>> sys.getsizeof(1 << 60) 36 >>> sys.getsizeof(1 << 90) 40

Los 24 bytes base entonces son la estructura PyObject_VAR_HEAD , que contiene el tamaño del objeto, el recuento de referencias y el puntero de tipo (cada uno de 8 bytes / 64 bits en mi plataforma OS X de 64 bits).

En Python 2, los enteros <= sys.maxint pero> = -sys.maxint - 1 se almacenan usando una estructura más simple que almacena solo el valor único:

typedef struct { PyObject_HEAD long ob_ival; } PyIntObject;

porque esto usa PyObject lugar de PyVarObject no hay campo ob_size en la estructura y el tamaño de la memoria está limitado a solo 24 bytes; 8 para el valor long , 8 para el recuento de referencia y 8 para el puntero del objeto tipo.