理解python内存分配和释放

Jun*_* Gu 6 python memory memory-management

我最近遇到了关于python内存分配的这篇文章.

在这个页面中,它描述了python的内存使用情况,并且在那里有一个显示整数列表的深度复制的示例.我自己在Python 2.7上做了基准测试

Line #    Mem usage    Increment   Line Contents
================================================
     4   28.051 MiB    0.000 MiB   @profile
     5                             def function():
     6   59.098 MiB   31.047 MiB       x = list(range(1000000))  # allocate a big list
     7  107.273 MiB   48.176 MiB       y = copy.deepcopy(x)
     8   99.641 MiB   -7.633 MiB       del x
     9   99.641 MiB    0.000 MiB       return y
Run Code Online (Sandbox Code Playgroud)

所以直接删除x只删除x和所有对整数的引用到x吗?

这样做也无济于事(那么del x和del x [:]有什么区别?):

Line #    Mem usage    Increment   Line Contents
================================================
     4   28.047 MiB    0.000 MiB   @profile
     5                             def function():
     6   59.094 MiB   31.047 MiB       x = list(range(1000000))  # allocate a big list
     7  107.270 MiB   48.176 MiB       y = copy.deepcopy(x)
     8   99.637 MiB   -7.633 MiB       del x[:]
     9   99.637 MiB    0.000 MiB       return y
Run Code Online (Sandbox Code Playgroud)

与深度复制相反,如果我使用复制,删除后似乎内存恢复到新创建x时的先前状态

Line #    Mem usage    Increment   Line Contents
================================================
     4   28.039 MiB    0.000 MiB   @profile
     5                             def function():
     6   59.090 MiB   31.051 MiB       x = list(range(1000000))  # allocate a big list
     7   66.895 MiB    7.805 MiB       y = copy.copy(x)
     8   59.262 MiB   -7.633 MiB       del x[:]
     9   59.262 MiB    0.000 MiB       return y
Run Code Online (Sandbox Code Playgroud)

对于dict:

Line #    Mem usage    Increment   Line Contents
================================================
     4   28.051 MiB    0.000 MiB   @profile
     5                             def function():
     6  100.523 MiB   72.473 MiB       x = dict((e, e) for e in xrange(1000000))
     7  183.398 MiB   82.875 MiB       y = copy.deepcopy(x)
     8  135.395 MiB  -48.004 MiB       del x
     9  135.395 MiB    0.000 MiB       return y
Run Code Online (Sandbox Code Playgroud)

对于列表列表(与整数列表比较,我假设del x或del x [:]只删除堆上的那个巨大的数组列表?):

Line #    Mem usage    Increment   Line Contents
================================================
     4   28.043 MiB    0.000 MiB   @profile
     5                             def function():
     6  107.691 MiB   79.648 MiB       x = [[] for _ in xrange(1000000)]
     7  222.312 MiB  114.621 MiB       y = copy.deepcopy(x)
     8  214.680 MiB   -7.633 MiB       del x[:]
     9  214.680 MiB    0.000 MiB       return y
Run Code Online (Sandbox Code Playgroud)

所以我想问:

  1. 那么,如果没有办法要求归还整数占用的内存?整数也是一个对象吗?为什么内存根本没有被释放?只是整数不能声称?还是漂浮和串?对象引用也是?
  2. 为什么内存为-7 MB?是因为列表,实现为数组列表,从堆中释放?
  3. 无论是列表还是字典,del x只能释放数据结构本身(我的意思是数组列表结构,或dict结构),但整数,对象引用可以标记为空闲,但不能返回系统?

在这个例子中,如何在x中释放所有下划线列表?

Line #    Mem usage    Increment   Line Contents
================================================
     4   28.047 MiB    0.000 MiB   @profile
     5                             def function():
     6  248.008 MiB  219.961 MiB       x = [list(range(10)) for _ in xrange(1000000)]
     7  502.195 MiB  254.188 MiB       y = copy.deepcopy(x)
     8  494.562 MiB   -7.633 MiB       del x[:]
     9  494.562 MiB    0.000 MiB       return y
Run Code Online (Sandbox Code Playgroud)

Jon*_*ler 1

长话短说

\n

del不像 C 中那样释放变量,它只是表示您不再需要它。接下来发生的是实现细节。

\n

理由

\n

所以这里发生的事情del并不内存,它只是告诉 python 你已经完成了变量的处理。具体来说:

\n
\n

7.5。德尔声明

\n

del_stmt ::= \xe2\x80\x9cdel\xe2\x80\x9d target_list

\n

删除是递归定义的,与定义赋值的方式非常相似。这里没有详细说明,而是提供一些提示。

\n

删除目标列表会从左到右递归地删除每个目标。

\n

删除名称会从本地或全局命名空间中删除该名称的绑定,具体取决于该名称是否出现在同一代码块的全局语句中。如果名称未绑定,则会引发 NameError 异常。

\n

属性引用、订阅和切片的删除被传递给所涉及的主要对象;删除切片通常相当于分配正确类型的空切片(但即使这也是由切片对象决定的)。

\n
\n

请注意,没有提到释放内存。相反,你告诉 python 它可以用该内存做“任何它想做的事”。在这种情况下,您的 python 实现(我假设是 CPython)将内存存储在内存缓存中以供以后使用。这使得 python 运行得更快,因为以后不需要分配那么多内存。

\n

例子

\n

考虑这个例子,我们del x然后再次创建一个副本y。请注意,第二次复制期间分配的内存量小于第一次复制期间分配的内存量。这是因为内存被重复使用。如果我们再次这样做,我们会发现在第三次复制期间几乎没有分配任何内存,因为 python 只是重新使用之前分配的内存:

\n
Line #    Mem usage    Increment   Line Contents\n================================================\n     4   34.777 MiB    0.000 MiB   @profile\n     5                             def function():\n     6   37.504 MiB    2.727 MiB       x = [list(range(10)) for _ in xrange(10000)]\n     7   40.773 MiB    3.270 MiB       y = copy.deepcopy(x)\n     8   40.773 MiB    0.000 MiB       del x\n     9   41.820 MiB    1.047 MiB       y2 = copy.deepcopy(y)\n    10   41.820 MiB    0.000 MiB       del y2\n    11   41.824 MiB    0.004 MiB       y3 = copy.deepcopy(y)\n    12   41.824 MiB    0.000 MiB       return y\n
Run Code Online (Sandbox Code Playgroud)\n

来源

\n

优秀的“博客”:http://www.evanjones.ca/memoryallocator/

\n

http://effbot.org/pyfaq/why-doesnt-python-release-the-memory-when-i-delete-a-large-object.htm

\n