python - 这个for循环中是什么占用了内存?

标签 python memory memory-management

我正在使用 memory_profiler 包(从 pip 下载),更具体地说,通过首先创建临时列表与循环“迭代器”来查看循环列表的内存效率列表”。

这是我不久前遇到的一个问题,我想对我的解决方案进行基准测试。问题是我需要将列表中的每个元素与同一列表中的下一个元素进行比较,直到所有元素都已被“处理​​”。所以我猜这将是一个 O(n^2) 解决方案(如果选择最简单的解决方案,对于列表中的每个元素,循环遍历列表)。

无论如何,下面的三个函数都在做同样的事情(或多或少);循环遍历一个以自身偏移量压缩的列表。

import cProfile

@profile
def zips():
    li = range(1,20000000)
    for tup in zip(li,li[1:]):
        pass
    del li

@profile
def izips():
    from itertools import izip
    li = range(1,20000000)
    for tup in izip(li,li[1:]):
        pass
    del li

@profile
def izips2():
    from itertools import izip
    li = range(1,20000000)
    for tup in izip(li,li[1:]):
        del tup
    del li



if __name__ == '__main__':
    zips()
    # izips()
    # izips2()

(对我来说)令人惊讶的部分是内存使用情况,首先我运行 zips() 函数,虽然我认为我已经清理干净了,但最终我仍然有 ~1.5 GB 的内存:

ipython -m memory_profiler python_profiling.py 
Filename: python_profiling.py

Line #    Mem usage    Increment   Line Contents
================================================
    10                             @profile
    11    27.730 MB     0.000 MB   def zips():
    12   649.301 MB   621.570 MB    li = range(1,20000000)
    13  3257.605 MB  2608.305 MB    for tup in zip(li,li[1:]):
    14  1702.504 MB -1555.102 MB        pass
    15  1549.914 MB  -152.590 MB    del li

然后我关闭解释器实例并重新打开它以运行下一个测试,即 izips() 函数:

ipython -m memory_profiler python_profiling.py 
Filename: python_profiling.py

Line #    Mem usage    Increment   Line Contents
================================================
    17                             @profile
    18    27.449 MB     0.000 MB   def izips():
    19    27.449 MB     0.000 MB    from itertools import izip
    20   649.051 MB   621.602 MB    li = range(1,20000000)
    21  1899.512 MB  1250.461 MB    for tup in izip(li,li[1:]):
    22  1746.922 MB  -152.590 MB        pass
    23  1594.332 MB  -152.590 MB    del li

最后我运行了一个测试(再次在重新启动解释器之后),我尝试显式删除 for 循环中的元组,以尝试确保它的内存将被释放(也许我不认为正确吗?)。事实证明这并没有什么区别,所以我猜测要么我没有提示 GC,要么这不是我的内存开销的来源。

ipython -m memory_profiler python_profiling.py 
Filename: python_profiling.py

Line #    Mem usage    Increment   Line Contents
================================================
    25                             @profile
    26    20.109 MB     0.000 MB   def izips2():
    27    20.109 MB     0.000 MB    from itertools import izip
    28   641.676 MB   621.566 MB    li = range(1,20000000)
    29  1816.953 MB  1175.277 MB    for tup in izip(li,li[1:]):
    30  1664.387 MB  -152.566 MB        del tup
    31  1511.797 MB  -152.590 MB    del li

底线: 我认为 for 循环本身的开销很小,因此,我预计只会多于 ~620.000 MB(存储列表所需的内存),但看起来我有 ~2 个大小的列表20.000.000 内存+更多开销。谁能帮我解释一下这些内存的用途是什么? (每次运行结束时是什么占用了约 1.5 GB 的空间?)

最佳答案

请注意,操作系统以 block 的形式分配内存,并且不一定一次性回收所有内存。我发现内存分析包非常不准确,因为它似乎没有考虑到这一点。

您的 li[1:] 切片创建一个包含 (2*10**7) - 1 个元素的列表,几乎是一个全新的副本,轻松将列表翻倍列表所需的内存空间。 zip() 调用还返回一个完整的新列表对象,即压缩操作的输出,同样需要内存来存储中间结果,以及 2000 万个 2 元素元组。

您可以使用新的迭代器而不是切片:

def zips():
    from itertools import izip
    li = range(1,20000000)
    next_li = iter(li)
    next(next_li)  # advance one step
    for tup in izip(li, next_li):
        pass
    del li

iter() 调用返回的列表迭代器更加轻量级;它只保留对原始列表的引用和一个指针。将其与 izip() 结合使用也可以避免创建输出列表。

关于python - 这个for循环中是什么占用了内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18568564/

相关文章:

cocoa - 具有 "copy"属性的 NSURL 属性。漏水了吗?

python - 错误 : Error when checking model input: expected dense_input_6 to have shape (None, 784) 但得到形状为 (784L, 1L) 的数组

python - 按小时分组,同时考虑夏令时

c++ - 如何在C++程序中使用hbw_malloc库?

c++ - 在构造函数中使用 std::vector 损坏内存

c - 指针对齐问题

安卓内存分配

python - 如果在 xpath (lxml) 中找不到节点/标签,如何返回字符串或匹配空

python - 来自字典列表的字典的数据框?

node.js - Node : What happen if not close oracle connection