Сколько байтов на элемент в списке Python (кортеже)?
-
02-07-2019 - |
Вопрос
Например, сколько памяти требуется для хранения списка из миллиона (32-битных) целых чисел?
alist = range(1000000) # or list(range(1000000)) in Python 3.0
Решение 2
Полезные ссылки:
Как получить размер памяти/использование объекта Python
Размеры памяти объектов Python?
если вы поместите данные в словарь, как нам рассчитать размер данных?
Однако они не дают однозначного ответа.Путь:
Измерьте память, потребляемую интерпретатором Python со списком или без него (используйте инструменты ОС).
Используйте сторонний модуль расширения, который определяет своего рода sizeof(PyObject).
Обновлять:
Рецепт 546530:Размер объектов Python (пересмотренный)
import asizeof
N = 1000000
print asizeof.asizeof(range(N)) / N
# -> 20 (python 2.5, WinXP, 32-bit Linux)
# -> 33 (64-bit Linux)
Другие советы
"Это зависит." Python выделяет пространство для списков таким образом, чтобы достичь амортизированное постоянное время для добавления элементов в список.
На практике это означает, что в текущей реализации...в списке всегда есть место, выделенное для количества элементов, равного степени двойки.Таким образом, range(1000000) фактически выделит список, достаточно большой, чтобы вместить 2^20 элементов (~ 1,045 миллиона).
Это всего лишь пространство, необходимое для хранения самой структуры списка (которая представляет собой массив указателей на объекты Python для каждого элемента).32-битная система потребует 4 байта на элемент, 64-битная система будет использовать 8 байт на элемент.
Кроме того, вам нужно место для хранения самих элементов.Это широко варьируется.Для небольших целых чисел (в настоящее время от -5 до 256) дополнительное пространство не требуется, но для больших чисел Python выделяет новый объект для каждого целого числа, которое занимает 10–100 байт и имеет тенденцию к фрагментации памяти.
Нижняя граница: все сложно и списки Python нет хороший способ хранения больших однородных структур данных.Для этого используйте array
модуль или, если вам нужно выполнить векторизованную математику, используйте NumPy.
PS. Кортежи, в отличие от списков, не предназначен чтобы к ним постепенно добавлялись элементы.Я не знаю, как работает распределитель, но даже не думаю использовать его для больших структур данных :-)
Обращение к «кортежной» части вопроса
Объявление PyTuple CPython в типичной конфигурации сборки сводится к следующему:
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
};
Размер экземпляра PyTuple фиксируется во время его создания и не может быть изменен впоследствии.Количество байтов, занимаемых PyTuple, можно рассчитать как
sizeof(size_t) x 2 + sizeof(void*) x (n_items + 1)
.
Это дает мелкий размер кортежа.Получить полный размер, вам также необходимо добавить общее количество байтов, потребляемых графом объектов, корнем которого является PyTuple::items[]
множество.
Стоит отметить, что процедуры построения кортежа гарантируют, что когда-либо будет создан только один экземпляр пустого кортежа (singleton).
Использованная литература:Python.h, объект.h, tupleobject.h, tupleobject.c
Новая функция,
getsizeof()
, принимает объект Python и возвращает количество памяти, используемой объектом, измеренной в байтах.Встроенные объекты возвращают правильные результаты;Сторонние расширения не могут быть, но могут определить__sizeof__()
метод, возвращающий размер объекта.
kveretennicov@nosignal:~/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
Очевидно, что возвращаемые числа не включают память, потребляемую содержащимися объектами (sys.getsizeof(1) == 12).
Я почти уверен, что это зависит от реализации.Конечно, это зависит от внутреннего представления целых чисел — вы не можете предполагать, что они будут храниться как 32-битные, поскольку Python предоставляет вам сколь угодно большие целые числа, поэтому, возможно, маленькие целые числа хранятся более компактно.
На моем Python (2.5.1 в Fedora 9 на Core 2 duo) размер VmSize до выделения составляет 6896 КБ, после — 22684 КБ.После назначения еще одного миллиона элементов VmSize достигает 38340 КБ.Это очень грубо указывает на около 16 000 КБ для 1 000 000 целых чисел, что составляет около 16 байт на целое число.Это предполагает много накладных расходов на список.Я бы отнесся к этим цифрам с большой долей скептицизма.
Меня беспокоит, почему вы спрашиваете.Вы пытаетесь выяснить, сколько памяти вам понадобится для конкретной реализации?Скажем, вы собираетесь прочитать 10 000 000 виджетов и хотите знать, сколько оперативной памяти это высосет?
В этом случае вместо того, чтобы пытаться выяснить, сколько оперативной памяти занимает каждый виджет, выясните, сколько оперативной памяти занимают, скажем, 10 000 виджетов, и умножьте это значение, чтобы получить фактический размер.