Man*_*ain 22 python memory python-internals
这是我的代码:
from memory_profiler import profile
@profile
def mess_with_memory():
huge_list = range(20000000)
del huge_list
print "why this kolaveri di?"
Run Code Online (Sandbox Code Playgroud)
当我从解释器运行时,这就是输出:
3 7.0 MiB 0.0 MiB @profile
4 def mess_with_memory():
5
6 628.5 MiB 621.5 MiB huge_list = range(20000000)
7 476.0 MiB -152.6 MiB del huge_list
8 476.0 MiB 0.0 MiB print "why this kolaveri di"
Run Code Online (Sandbox Code Playgroud)
如果你注意到输出,创建巨大的列表消耗621.5 MB,而删除它只需释放152.6 MB.当我检查文档时,我发现了以下声明:
the statement del x removes the binding of x from the namespace referenced by the local scope
Run Code Online (Sandbox Code Playgroud)
所以我猜,它并没有删除对象本身,而只是取消绑定它.但是,它在解除绑定方面做了什么呢?它释放了如此多的空间(152.6 MB).有人可以请痛苦地向我解释这里发生了什么吗?
aba*_*ert 31
Python是一种垃圾收集语言.如果某个值不再可以从您的代码"到达",它最终会被删除.
del如您所见,该语句删除了变量的绑定.变量不是值,它们只是值的名称.
如果该变量是对任何值的唯一引用,则该值最终将被删除.特别是在CPython中,垃圾收集器建立在引用计数之上.因此,"最终"意味着"立即".*在其他实施中,它通常"很快".
如果有相同的值其它参考,但是,仅仅取消这些参考之一(无论是del x,x = None在离开这里的范围x存在,等)不干净东西了.**
这里还有另一个问题.我不知道memory_profiler模块(可能是这个模块)实际测量的是什么,但描述(谈论使用psutil)听起来像是从"外部"测量你的内存使用量.
当Python释放存储时,它并不总是 - 甚至通常 - 将其返回给操作系统.它在多个级别保持"自由列表",因此它可以更快地重新使用内存,而不是必须一直回到操作系统以要求更多.在现代系统中,这很少是一个问题 - 如果您再次需要存储,那么您拥有它是件好事; 如果你不这样做,它会在其他人需要它时立即被分页,并且永远不会被重新打包,所以这没有什么害处.
(最重要的是,上面我称之为"操作系统"实际上是一个由多个级别组成的抽象,从malloc库到核心C库再到内核/寻呼机,并且这些级别中至少有一个通常具有自己的免费清单.)
如果你想从内部角度追踪内存使用......那么,这很难.由于新tracemalloc模块,它在Python 3.4中变得更加容易.有各种第三方的模块(例如,heapy/ guppy,Pympler,meliae),尝试得到同样的与早期版本的信息,但是很难,因为正从各个分配器信息,系该信息的垃圾收集器,非常在PEP 445之前很难.
*在某些情况下,是对价值的参考...但只能从自身是无法访问的,可能是在一个周期内其他的引用.就垃圾收集器而言,这仍然被视为"无法访问",但就引用计数而言并非如此.因此,CPython还有一个"循环检测器",每隔一段时间就会运行一次,并找到可以互相访问但不能从任何其他人那里获取的循环,并清理它们.
**如果您在交互式控制台中进行测试,可能会隐藏对您的值的引用,这些引用难以跟踪,因此您可能会认为在没有的情况下已经删除了最后一个引用.在脚本中,它应该永远是可能的,如果不容易,要理出头绪.该gc模块可以提供帮助,调试器也可以提供帮助.不过,当然他们两个也给你新的方法来增加额外的隐藏引用.
| 归档时间: |
|
| 查看次数: |
5882 次 |
| 最近记录: |