Модель памяти Python

Одна вещь, которую я регулярно использую, это установка точки останова, но затем контроль за тем, что она делает. (На моей последней работе большинство остальных использовали Eclipse ... Я помню, как был удивлен, что никто не мог найти, как это сделать в Eclipse.)

Например, точка останова может не останавливаться, а просто записать сообщение в консоль. Это означает, что мне не нужно засорять мой код «System.out.println (...)», а затем перекомпилировать.

10
задан ooboo 29 June 2009 в 19:31
поделиться

4 ответа

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

Изменить: обратите внимание, что ссылки всегда относятся к объектам , а не к «переменным» - в Python (или Java) нет такой вещи, как «ссылка на переменную». Например:

>>> n = 23
>>> a = [n,n]
>>> print id(n), id(a[0]), id(a[1])
8402048 8402048 8402048
>>> n = 45
>>> print id(n), id(a[0]), id(a[1])
8401784 8402048 8402048

Из первого отпечатка видно, что обе записи в списке a относятся к одному и тому же объекту, к которому относится n , но когда n переназначен , it теперь относится к другому объекту, а обе записи в a по-прежнему относятся к предыдущему.

array.array (из Python стандартный библиотечный модуль array ) очень отличается от списка: он хранит компактные копии однородного типа, занимая столько битов на элемент, сколько необходимо для хранения копий значений этого типа. Все нормальные контейнеры хранят ссылки (внутренне реализованные в среде выполнения Python с кодом C как указатели на структуры PyObject: каждый указатель в 32-битной сборке занимает 4 байта, каждый PyObject не менее 16 или около того [включая указатель на тип, количество ссылок , реальная стоимость, и malloc округление вверх]), массивы - нет (поэтому они не могут быть разнородными, не могут содержать элементы, кроме нескольких базовых типов и т. д.).

Например, контейнер на 1000 элементов со всеми элементами будучи разными небольшими целыми числами (значения которых могут умещаться в 2 байта каждое), потребуется около 2000 байт данных в виде array.array ('h') , но около 20 000 в виде списка . Но если бы все элементы были одного и того же числа, массив все равно занимал бы 2000 байтов данных, список занимал бы только 20 или около того [[в каждом из этих случаев вам нужно добавить еще около 16 или 32 байта для объекта-контейнера собственно, в дополнение к памяти для данных]].

Однако, хотя в вопросе указано «массив» (даже в теге), я сомневаюсь, что его arr на самом деле является массивом - если он мы, он не мог сохранить (2 ** 32) * 2 (наибольшие значения int в массиве - 32 бита), и поведение памяти, указанное в вопросе, фактически не наблюдалось. Итак, вопрос, вероятно, на самом деле касается списка, а не массива.

Edit : комментарий @ooboo задает множество разумных уточняющих вопросов, и вместо того, чтобы пытаться раздавить подробное объяснение в комментарии I ' я перенес его сюда.

Это странно, в конце концов, как ссылка на целое число хранится? id (переменная) дает целое число, ссылка сама по себе является целым числом, не дешевле использовать целое число?

CPython хранит ссылки как указатели на PyObject (Jython и IronPython, написанные на Java и C #, используют неявные ссылки этих языков; PyPy, написанный на Python, имеет очень гибкую внутреннюю часть и может использовать множество различных стратегий)

id (v) дает (только на CPython) числовое значение указателя (просто как удобный способ однозначно идентифицировать объект). Список может быть неоднородным (некоторые элементы могут быть целыми числами, другие - объектами разных типов), поэтому хранить одни элементы в качестве указателей на PyObject и другие по-разному - просто неразумно (каждый объект также нуждается в указании типа, а в CPython - счетчик ссылок, по крайней мере) - array.array однороден и ограничен, поэтому он действительно может (и хранит) хранить копию элементов ' вместо этого назначено 2 ** 64 каждому слоту присвоения n, когда n имеет ссылка на 2 ** 64 ? Что происходит, когда когда мы говорим о популярной реализации с кодом C (за исключением таких контекстов, как этот, где первостепенное значение имеет проведение различия между языком и реализацией ;-). Тем не менее, различие весьма важно, и его стоит время от времени повторять.

17
ответ дан 3 December 2019 в 16:30
поделиться

В первом примере вы сохраняете одно и то же целое число len (arr) раз. Итак, python нужно просто сохранить целое число один раз в памяти и ссылаться на него len (arr) раз.

Во втором примере вы сохраняете len (arr) разных целых чисел. Теперь python должен выделить память для целых чисел len (arr) и ссылаться на них в каждом из слотов len (arr).

5
ответ дан 3 December 2019 в 16:30
поделиться

У вас есть только одна переменная n, но вы создаете много i ** 2.

Что происходит, так это то, что Python работает со ссылками. Каждый раз, когда вы выполняете array [i] = n , вы создаете новую ссылку на значение n . Не к переменной, заметьте, к значению. Однако во втором случае, когда вы выполняете array [i] = i ** 2 , вы создаете новое значение и ссылаетесь на это новое значение. Это, конечно, потребует гораздо больше памяти.

Фактически, Python будет продолжать повторно использовать одно и то же значение и просто использовать ссылки на него, даже если оно пересчитывается. Так, например:

l = []
x = 2
for i in xrange(1000000):
    l.append(x*2)

обычно не будет использовать больше памяти, чем

l = []
x = 2
for i in xrange(1000000):
    l.append(x)

. Однако в случае

l = []
x = 2
for i in xrange(1000000):
    l.append(i)

каждое значение i получит ссылку и, следовательно, будет храниться в памяти, используя много памяти по сравнению с другие примеры.

3
ответ дан 3 December 2019 в 16:30
поделиться

Как сказал Кендалл, включение ключа на устройстве в основном требует взлома. Однако есть люди, у которых есть причины скрывать данные с помощью ключа на устройстве. Если вы полны решимости это сделать, вы можете рассмотреть возможность использования SQLCipher для своей реализации. Это сборка SQLite, которая обеспечивает прозрачное шифрование всей БД на уровне страниц. На Mobile Orchard есть руководство по использованию его в приложениях для iPhone.

Есть люди, у которых есть свои причины скрывать данные с помощью ключа на устройстве. Если вы полны решимости это сделать, вы можете рассмотреть возможность использования SQLCipher для своей реализации. Это сборка SQLite, которая обеспечивает прозрачное шифрование всей БД на уровне страниц. На Mobile Orchard есть руководство по использованию его в приложениях для iPhone.

Есть люди, у которых есть свои причины скрывать данные с помощью ключа на устройстве. Если вы полны решимости это сделать, вы можете рассмотреть возможность использования
SQLCipher для своей реализации. Это сборка SQLite, которая обеспечивает прозрачное шифрование всей БД на уровне страниц. На Mobile Orchard есть руководство по использованию его в приложениях для iPhone.

плюс ноль или более внутренних границ, все из которых не пересекаются *. Если вы используете ненулевое число витков
для определения внутренней / внешней стороны, обязательно укажите внутренние границы в направлении, противоположном внешним границам (против часовой стрелки для внешних и по часовой стрелке для внутренних или наоборот), чтобы контурные интегралы внутри отверстий равны нулю.

К вашему сведению, это определение / представление было формализовано в спецификации OpenGIS Simple Features Specification ( PDF ).

Что касается представления:

I Вероятно, у нас есть массив ячеек из K Nx2 матриц, где первый элемент в массиве ячеек является внешней границей, а остальные элементы (если есть) в массиве ячеек являются внутренними границами.

0
ответ дан 3 December 2019 в 16:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: