"sys.getsizeof(int)" возвращает неоправданно большое значение?

Я хочу проверить размер типа данных int в Python:

import sys
sys.getsizeof(int)

Получается "436", что не имеет смысла для меня. В любом случае, я хочу знать, сколько байтов (2,4,..?) Int займет на моей машине.

1 ответ

Решение

Краткий ответ

Вы получаете размер класса, а не экземпляра класса. Вызов int чтобы получить размер экземпляра:

>>> sys.getsizeof(int())
24

Если этот размер все еще кажется немного большим, помните, что Python int сильно отличается от int в (например) в. В Python int является полноценным объектом. Это означает, что есть дополнительные накладные расходы.

Каждый объект Python содержит по крайней мере refcount и ссылку на тип объекта в дополнение к другому хранилищу; на 64-битной машине это занимает 16 байтов! int внутренние компоненты (как определено стандартной реализацией CPython) также со временем менялись, так что объем занимаемой дополнительной памяти зависит от вашей версии.

Некоторые подробности о int объекты в Python 2 и 3

Вот ситуация в Python 2. (Часть этого взята из сообщения в блоге Лорана Люса). Целочисленные объекты представлены в виде блоков памяти со следующей структурой:

typedef struct {
    PyObject_HEAD
    long ob_ival;
} PyIntObject;

PyObject_HEAD это макрос, определяющий хранилище для refcount и типа объекта. Это подробно описано в документации, и код можно увидеть в этом ответе.

Память выделяется большими блоками, поэтому для каждого нового целого числа нет узкого места. Структура для блока выглядит следующим образом:

struct _intblock {
    struct _intblock *next;
    PyIntObject objects[N_INTOBJECTS];
};
typedef struct _intblock PyIntBlock;

Сначала все они пусты. Затем каждый раз, когда создается новое целое число, Python использует память, на которую указывает next и приращения next указать на следующий свободный целочисленный объект в блоке.

Я не совсем уверен, как это изменится, когда вы превысите емкость обычного целого числа, но как только вы это сделаете, размер int становится больше. На моей машине, в Python 2:

>>> sys.getsizeof(0)
24
>>> sys.getsizeof(1)
24
>>> sys.getsizeof(2 ** 62)
24
>>> sys.getsizeof(2 ** 63)
36

В Python 3, я думаю, общая картина та же, но размер целых чисел увеличивается более постепенно:

>>> sys.getsizeof(0)
24
>>> sys.getsizeof(1)
28
>>> sys.getsizeof(2 ** 30 - 1)
28
>>> sys.getsizeof(2 ** 30)
32
>>> sys.getsizeof(2 ** 60 - 1)
32
>>> sys.getsizeof(2 ** 60)
36

Эти результаты, конечно, все зависит от оборудования! YMMV.

Изменчивость в целочисленном размере в Python 3 является намеком на то, что они могут вести себя больше как типы переменной длины (например, списки). И действительно, это оказывается правдой. Вот определение Cstruct за int объекты в Python 3:

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

Комментарии, сопровождающие это определение, обобщают представление целых чисел в Python 3. Ноль представлен не сохраненным значением, а объектом с нулевым размером (вот почему sys.getsizeof(0) является 24 байт в то время как sys.getsizeof(1) является 28). Отрицательные числа представлены объектами с отрицательным атрибутом размера! Так странно.

Другие вопросы по тегам