Подтвердить что ты не робот

Почему в Python требуется в три раза больше памяти?

В 64-битной системе целое число в Python занимает 24 байта. Это в 3 раза больше памяти, которая потребуется в, например, C для 64-битного целого. Теперь, я знаю, это потому, что целые числа Python являются объектами. Но для чего нужна дополнительная память? У меня есть свои догадки, но было бы хорошо знать наверняка.

4b9b3361

Ответ 1

Помните, что тип Python int не имеет ограниченного диапазона, как у C int; единственным ограничением является доступная память.

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

Вы можете найти источник longintrepr.h (тип Python 3 int традиционно назывался long типом в Python 2); он эффективно использует тип PyVarObject C для отслеживания целочисленного размера:

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

Массив ob_digit хранит "цифры" шириной 15 или 30 бит (в зависимости от вашей платформы); поэтому в моей 64-битной системе OS X целое число до (2 ^ 30) - 1 использует 1 цифру:

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

но если вы используете 2 30-битные цифры в номере, понадобятся дополнительные 4 байта и т.д.:

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

Основными 24 байтами являются структура PyObject_VAR_HEAD, содержащая размер объекта, счетчик ссылок и указатель типа (каждые 8 байтов /64 бита на моей 64-битной платформе OS X).

В Python 2 целые числа <= sys.maxint но> = -sys.maxint - 1 хранятся с использованием более простой структуры, хранящей только одно значение:

typedef struct {
    PyObject_HEAD
    long ob_ival;
} PyIntObject;

поскольку вместо PyVarObject используется PyObject в PyVarObject нет поля ob_size а размер памяти ограничен всего 24 байтами; 8 для long значения, 8 для счетчика ссылок и 8 для указателя объекта типа.

Ответ 2

Из longintrepr.h мы видим, что объект "int" Python определен с помощью этой структуры C:

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

Digit - это 32-разрядное значение без знака. Основная часть пространства занимает заголовок объекта с переменным размером. Из object.h мы можем найти его определение:

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;

Мы видим, что мы используем 64-разрядную версию Py_ssize_t, предполагающую 64-битную систему, для хранения количества цифр в значении. Это возможно расточительно. Мы также видим, что общий заголовок объекта имеет 64-битный счетчик ссылок и указатель на тип объекта, который также будет 64-разрядным хранилищем. Счетчику ссылок необходимо, чтобы Python знал, когда следует освободить объект, и указатель на тип объекта необходим, чтобы знать, что у нас есть int, а не, скажем, строка, поскольку структуры C не имеют возможности протестировать тип объект от произвольного указателя.

_PyObject_HEAD_EXTRA не имеет ничего общего с большинством построений python, но может использоваться для хранения связанного списка всех объектов Python в куче, если сборка включает этот параметр, используя еще два указателя по 64 бита каждый.