【问题标题】:understanding python memory allocation and free up了解python内存分配和释放
【发布时间】:2018-01-23 01:41:38
【问题描述】:

我最近遇到了this article关于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

所以直接删除 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

与 deepcopy 相比,如果我使用复制,删除后似乎内存恢复到新创建 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

对于字典:

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

对于列表列表(与整数列表相比,我假设 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

所以我想问一下:

  1. 那么如果没有办法收回那些被整数占用的内存呢?整数也是一个对象,对吗?为什么内存根本没有被释放?不能只声明整数?还是浮动和字符串?对象引用也一样?
  2. 为什么有 -7 MB 的内存?是不是因为实现为数组列表的列表从堆中释放出来了?
  3. 不管是list还是dict,del x只能释放数据结构本身(我的意思是数组list结构,或者dict结构),但是整数、对象引用可以标记为free,但不能返回系统?

在这个例子中,我该如何或者是否有办法释放 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

【问题讨论】:

    标签: python memory memory-management


    【解决方案1】:

    TL;DR

    del 不像 C 中那样释放变量,它只是说您不再需要它。然后发生的是一个实现细节。

    理由

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

    7.5。 del 语句

    del_stmt ::= “del” target_list

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

    删除一个目标列表递归删除每个目标,从左到右。

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

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

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

    示例

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

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

    来源

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-25
      • 1970-01-01
      • 2011-12-09
      • 1970-01-01
      • 2013-03-04
      • 2021-04-21
      • 1970-01-01
      相关资源
      最近更新 更多