Python 文档和实现中“对象在内存中的地址”的细微差别

flo*_*w2k 4 python memory

Python 中函数的接口id()对我来说很清楚:\n“对象\xe2\x80\x99s 身份一旦创建就永远不会改变” [1],并且\n“这是一个保证唯一的整数并且该对象在其生命周期内保持不变。” [2]

\n\n

但[1]中的这个说法让我很困惑:“你可能会认为它是内存中的对象\xe2\x80\x99s地址”。

\n\n

问题是不清楚对象在内存中的地址是什么以及它如何变化。我认为这确实是一个实现细节。这个问题似乎表明,要使语言参考中的这一陈述成立,对象的虚拟地址在实现中决不能改变。

\n\n

我的问题是:

\n\n
    \n
  1. 这个地址是指虚拟内存地址还是物理内存地址?任何进程的物理地址都是由操作系统在运行时确定的,因此我不明白它如何是物理的。

  2. \n
  3. 实现如何保持虚拟对象地址相同,同时仍然避免内部碎片?相比之下,在 Java 中,JVM 例程在 GC 期间移动对象。

  4. \n
\n

use*_*968 5

事实上,对象id的 是由实现定义的,只要它 a)其生命周期内是唯一且恒定的(虽然与这个问题无关:这确实意味着id如果第一个对象的生命周期结束,两个对象可以具有相同的值) )。

CPython 实现确实具有不变性,即对象始终固定在其原始内存位置并且从不移动。当涉及到与 C 的互操作性时,这具有巨大的好处,因为只要对象保持活动状态(通常只是递增的引用计数器),您就可以自由地传递指针,这些指针将保持有效。

鉴于此,CPython 解释器仅使用对象的虚拟内存地址,如下所示id

  • 虚拟地址对于每个对象都是唯一的,因为可以确定它们不是同一对象的任何两个对象必须位于不同的内存位置。
  • 使用对象的虚拟地址始终id是安全的,因为如果存储该id对象,删除原始对象,重新使用id我以前见过这个对象吗?)并陷入混乱,他就违反了以下规则:id只有当它所代表的对象还活着时,the才有效。

另请注意,重新分配不会更改对象的虚拟地址。例如,该list对象有一个指向元素向量的内部指针。id-object 的是其自身list的虚拟地址PyListObject。当列表增长并需要重新分配/移动到其他地方时,仅更改内部指针;留PyListObject在原来的地方,因此它id保持不变。

以下是current 中内置函数的完整定义id()HEAD

static PyObject *
builtin_id(PyModuleDef *self, PyObject *v)
{
    return PyLong_FromVoidPtr(v);
}
Run Code Online (Sandbox Code Playgroud)

没有烟,没有镜子。这只是指针。