Python内存模型

2023-11-27

我有一个很大的清单 假设我这样做(是的,我知道代码非常不Python,但为了示例......):

n = (2**32)**2
for i in xrange(10**7)
  li[i] = n

工作正常。然而:

for i in xrange(10**7)
  li[i] = i**2

消耗大量内存。我不明白为什么 - 存储大数字需要更多位,而在 Java 中,第二个选项确实更节省内存......

有人对此有解释吗?


Java 对一些值类型(包括整数)进行特殊处理,以便它们按值存储(而不是像其他所有内容一样按对象引用存储)。 Python 不会对此类类型进行特殊处理,因此可以将 n 分配给多个条目在列表中(或其他普通的 Python 容器)不必复制。

编辑:请注意,引用始终是objects,而不是“变量”——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还是参考上一篇。

An array.array(来自Python标准库模块array)与列表有很大不同:它保留同类类型的紧凑副本,每个项目占用存储该类型值的副本所需的尽可能少的位。所有普通容器都保留引用(在 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 位),并且实际上不会观察到问题中报告的内存行为。所以,问题实际上可能是关于列表,而不是数组。

Edit:@ooboo 的评论提出了许多合理的后续问题,我并没有试图在评论中压缩详细的解释,而是将其移至此处。

不过,这很奇怪——毕竟,怎么样? 对存储的整数的引用? id(variable) 给出一个整数, 引用本身是一个整数,不是 使用整数更便宜吗?

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

id(v)给出(仅在 CPython 上)指针的数值(就像唯一标识对象的便捷方法)。列表可以是异构的(某些项可能是整数,其他项可能是不同类型的对象),因此将某些项存储为 PyObject 的指针和其他不同的项并不是一个明智的选择(每个对象还需要类型指示,并且在 CPython 中,至少引用计数)--array.array是同构且有限的,因此它可以(并且确实)确实存储项目值的副本而不是引用(这通常更便宜,但不适用于同一项目出现很多的集合,例如稀疏数组,其中绝大多数项目数为 0)。

语言规范完全允许 ​​Python 实现尝试更微妙的优化技巧,只要它保持语义不变,但据我所知,目前没有一个可以解决这个特定问题(您可以尝试破解 PyPy 后端,但不要这样做)如果检查 int 与非 int 的开销超过了预期的收益,请不要感到惊讶)。

另外,如果我 分配的2**64改为每个插槽 分配 n,当 n 持有 a 参考2**64?当发生什么 我只写1?

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

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

在实践中,CPython(我相信其他实现,但我不太熟悉它们的内部结构)使用一个足够的副本small整数(以 PyObject 形式保留一些预定义的 C 数组,其中包含一些小整数值,以便在需要时使用或重用),但通常不会特意寻找其他现有的可重用对象。

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

有时它比 Python 更难记住一种语言它有几个实现可能(合法且正确地)在许多此类细节上有所不同 - 每个人,包括像我这样的学究,在谈论流行的 C 编码实现时倾向于只说“Python”而不是“CPython”(除了在像这样的上下文中,区分语言和实现是至关重要的;-)。尽管如此,区别is非常重要,并且值得偶尔重复一次。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python内存模型 的相关文章

随机推荐

  • 亚马逊商城 API [已关闭]

    Closed 这个问题需要多问focused 目前不接受答案 我期望亚马逊市场网络服务像任何其他网络服务一样简单 但事实并非如此 似乎有一些关于市场产品提要的信息 任何人都可以帮助我如何开始上传新产品 一步一步 因为我是新手 以及更新数量或
  • 使用elasticsearch-dsl的delete方法时版本冲突

    因此 我们在 Django 项目中使用elasticsearch 并且使用elasticsearch dsl python 库 我们在生产中遇到以下错误 ConflictError 409 took 7 timed out false to
  • ASP.Net MVC 中的自我 AJAX 更新部分视图/控制器和复制 div

    我对 MVC 的部分看法如下 div div 在该 div 内有一个表单 它使用 AJAX 调用控制器并返回相同的部分视图 问题是调用视图的结果替换了 div 的内容 而不是整个 div 我最终得到 div div div div 根据我一
  • 真(非伪)随机数生成器。外面有什么? [关闭]

    Closed 这个问题不符合堆栈溢出指南 目前不接受答案 我正在寻找能够生成真实随机数的经济实惠的解决方案 我已经发现LavaRnd 这是一个密码学上合理的随机数生成器 有人有这个领域的经验和 或了解其他解决方案吗 PS 恕我直言 这个问题
  • API 获取和浏览器崩溃后 Swagger UI 冻结

    我有一个 ASP NET WebAPI 项目 我试图用 Swagger UI 替换旧的 XmlDocumentationProvider 页面 我正在使用webAPI 5 3 1 的 swashbuckle swagger努吉特包 我能够导
  • 如何创建非持久性 EJB 3.1 计时器?

    使用 NetBeans 7 1 GlassFish 3 1 我创建了一个新的 TimerSessionBean Stateless public class NewTimerSessionBean implements NewTimerSe
  • 如何计算孩子的数量?

    我有一个清单 ul li li li li li li ul 我需要 jQuery 来计算列表中的项目数 您可以使用 length 像这样 var count ul li length length告诉选择器找到了多少个匹配项 因此这会计算
  • 更新 mongodb 中的嵌套数组

    我在 mongodb 中有一个文档 其中包含需要更新的 2 级深度嵌套对象数组 如下所示 id 1 items id 2 blocks id 3 txt hello 如果只有一层深数组 我可以使用位置运算符来更新其中的对象 但对于第二层 我
  • Google App Engine 标准环境还是灵活环境?

    我陷入了选择 Google App Engine Standard 和 Google App Engine Standard 之间的抉择 适合现实世界生产的灵活环境 我肯定想使用Java 需要使用Firebase 最新版本 进行身份验证和推
  • 为子字符串搜索建立索引?

    我想在数十亿个字符串中进行常规子字符串搜索 这个要求与一般的全文搜索有点不同 因为我希望查询 ubst 也可以点击 substr Lucene 或 Sphinx 能够做到这一点吗 如果没有 您认为最好的方法是什么 这种情况下的最佳索引结构是
  • iOS 和 Android 共享 HTTP 深度链接?

    我正在尝试通过 URL 通过电子邮件等共享 启动我的本机应用程序 Android 似乎只响应 HTTP 深层链接 URL 例如 http myapp com stuff 并且 iOS 仅响应非 HTTP 自定义深层链接 URL 例如 mya
  • SPA - Firebase 和 .Net WebApi 2 身份验证

    我有一个用 AngularJs 编写的单页应用程序 此时框架无关紧要 该应用程序托管在 IIS 中 它由 index html 和一堆客户端资产组成 在后端 我有 WebApi 2 它也作为单独的应用程序托管在 IIS 中 对于客户端身份验
  • 不安全的 JavaScript 尝试通过 URL 访问框架

    我已将 Vimeo 合并到我正在构建的 WordPress 主题中 但出现以下错误 不安全的 JavaScript 尝试通过 URL 访问框架http themes ibrogram com beta blog 来自带有 URL 的框架ht
  • 停止在 jqgrid 中调整列大小

    如何使 jqgrid 的所有列不可调整大小 目前我认为每一列都必须指定属性 ressized false 我可以为整个网格指定吗 从版本 3 8 2 开始 jqGrid 支持一项非常有用的功能 栏模板 我赞扬该功能可能不太正确 因为该功能是
  • 当浏览器重新加载/返回时,如何防止数据库被再次写入?

    我正在编写一个小型 Web 应用程序 用于写入数据库 Perl CGI 和 MySQL CGI 脚本从表单中获取一些信息并将其写入数据库 然而 我注意到 如果我在网络浏览器上点击 重新加载 或 返回 它会再次将数据写入数据库 我不想要这个
  • Rails 返回:[BUG] 分段错误

    如果我跑rails s I get Users adam rvm gems ruby 1 9 3 p327 gems pg 0 13 2 lib pg ext bundle BUG Segmentation fault ruby 1 8 7
  • Java - 将小写转换为大写而不使用 toUppercase()

    我正在尝试创建一个简短的程序 将所有大写字母转换为小写字母 从命令行输入 以下编译但没有给出我期望的结果 这会是什么原因呢 例如 java toLowerCase BANaNa gt 给出香蕉的输出 public class toLower
  • VS2010 抛出“无法复制文件“obj\x86\Debug\[file].exe”,因为找不到该文件。”

    我正在编写一个 Windows Phone 8 游戏 需要许多支持桌面应用程序 关卡编辑器等 由于我只有 VS 的 Express 版本 因此我使用 2010 for Windows Phone 来创建这些游戏 2012 不提供创建 Win
  • 创建零填充 JavaScript 数组的最有效方法?

    在 JavaScript 中创建任意长度的零填充数组的最有效方法是什么 ES6引入Array prototype fill 它可以这样使用 new Array len fill 0 不确定它是否很快 但我喜欢它 因为它很短并且具有自我描述性
  • Python内存模型

    我有一个很大的清单 假设我这样做 是的 我知道代码非常不Python 但为了示例 n 2 32 2 for i in xrange 10 7 li i n 工作正常 然而 for i in xrange 10 7 li i i 2 消耗大量