您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

Python内存模型

Python内存模型

Java特例一些值类型(包括整数),以便它们按值存储(而不是像其他所有对象一样按对象引用存储)。Python并不对此类类型进行特殊处理,因此无需 为列表 (或其他常规Python容器)中的多个条目分配n即可进行复制。

编辑:请注意,引用始终是对 对象 的引用,而不是“对变量的引用”-在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重新分配时, 现在引用的对象是不同的对象,而两个条目中的条目a仍然引用前一个对象。

一个array.array(Python标准库模块阵列)是从列表中非常不同:它保持一个均匀的类型的紧凑副本,每件少的比特在需要该类型的值的存储副本服用。所有普通容器都保留引用(在C编码的Python运行时中内部实现为指向PyObject结构的指针:在32位版本上,每个指针占用4个字节,每个PyObject至少16个左右(包括类型指针,引用计数) ,实际值和malloc向上舍入]),数组则不会(因此它们不能是异构的,除了一些基本类型之外,不能有任何项,等等)。

例如,一个1000项的容器(所有项都是不同的小整数)(每个值的大小可以容纳2个字节),将需要大约2,000个字节的数据array.array('h'),而要使用大约20,000个数据list。但是,如果所有项目都具有相同的编号,则数组仍将占用2,000个字节的数据,列表将仅占用20个左右[[在每种情况下,您必须为容器对象添加大约16或32个字节适当的,除了用于数据的内存]]。

但是,尽管这个问题说的是“数组”(即使在标签中),但我怀疑它arr实际上是数组-如果是,它就无法存储(2 * 32) 2(数组中最大的int值为32)位)和问题中报告的内存行为实际上不会被观察到。因此,问题实际上可能与列表有关,而不是数组。

:@ooboo的评论提出了许多合理的后续问题,而不是尝试在评论中压缩详细的说明,我将其移至此处。

但是,这很奇怪-毕竟如何存储对整数的引用?id(variable)给出一个整数,引用本身就是一个整数,使用该整数便宜吗?

cpython将引用存储为指向PyObject的指针(用Java和C#编写的Jython和IronPython使用这些语言的隐式引用;用Python编写的PyPy具有非常灵活的后端,可以使用许多不同的策略)

id(v)提供(仅在cpython上)指针的数字值(作为唯一标识对象的简便方法)。列表可以是异类的(某些项可能是整数,其他项可能是不同类型的对象),所以将某些项存储为指向PyObject的指针和其他项的指针(每个对象也需要类型指示,在cpython中还需要类型指示)不是明智的选择。至少array.array是引用计数)-是同质且受限制的,因此它确实可以(并且确实)存储项目值的副本而不是引用(这通常比较便宜,但不适用于同一项目显示很多的集合,例如稀疏数组,其中大多数项目为0)。

语言规范将完全允许Python实现尝试更巧妙的技巧来进行优化,只要它保持语义不变即可,但据我所知,目前对此特定问题没有任何实现(您可以尝试破解PyPy后端,但不要这样做)。如果检查int和non- int的开销超过了预期的收益,请不要感到惊讶。

另外,2**64当n保留对n的引用时,如果我分配给每个插槽而不是分配n会有所不同2**64吗?我只写1会怎样?

这些是每个实现都可以完全实现的实现选择示例,因为不难保留语义(因此,假设3.1和3.2在此方面的行为也可能不同)。

当您使用int文字(或任何其他不可变类型的文字)或其他产生这种类型结果的表达式时,由实现决定是否无条件创建该类型的新对象,或花一些时间在这些对象之间进行检查,以查看是否存在可以重用的对象。

在实践中,cpython(我相信其他实现,但我对它们的内部知识不太熟悉)使用足够 小的 整数的单个副本(保留PyObject形式的一些小的整数值的预定义C数组,可以立即使用或可以根据需要进行重用),但通常不会竭尽所能寻找其他现有的可重用对象。

但是例如,同一函数中相同的文字常量可以轻松并方便地编译为对该函数常量表中单个常量对象的引用,因此这是非常容易实现的优化,我相信当前的每个Python实现都可以执行该优化。

有时可能很难记住,因为Python是 一门语言, 并且它有多种实现方式(在合法和正确的方面)可能在许多此类细节上有所不同- 每个人,包括像我这样的学徒,都倾向于只说“ Python”而不是“ “ cpython”在谈论流行的C编码实现时(在像这样的上下文中,将语言和实现之间的区别放在首位是例外;-)。尽管如此,区别 还是 很重要的,值得不时重复。

python 2022/1/1 18:34:47 有211人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶