识别内存性能分析器中的内存泄漏



我是Python的新手,我目前正在努力解决问题以提高我的编码技能。目前,我正在处理一个问题,我必须stable sort输入并输出反向稳定的排序值。我已经对它进行了编程并在网站的在线判断中执行了代码,对于一个测试用例(不知道测试用例),我得到了Memory Limit Exceeded错误。所以经过一番研究,我明白了代码中发生了memory leak,代码并不完全有效。因此,我安装了python的memory_profiler来监视进程的内存消耗以及对代码的内存消耗进行逐行分析。

请在下面找到输入详细信息、代码、输出和从memory_profiler中获取的内存分析。

输入:

8
1 2
16 3
11 2
20 3
3 5
26 4
7 1
22 4 

法典:

from collections import OrderedDict
@profile
def test_1():
    print "Enter the number: "
    n = raw_input()
    k = []
    v = []
    print "Enter ID and M: "
    for i in range(0,int(n)):
        a, b = raw_input().split(' ')
        k.append(a)
        v.append(b)
    d = OrderedDict(zip(k,v))
    sorted_items = sorted(d.items(), key=lambda (k,v):int(v), reverse=True)
    for i, j in sorted_items:
        print i, j
if __name__ == '__main__':
        test_1()

输出:

    Line #    Mem usage    Increment   Line Contents
================================================
     2   10.520 MiB    0.000 MiB   @profile
     3                             def test_1():
     4   10.531 MiB    0.012 MiB        print "Enter the number: "
     5   10.551 MiB    0.020 MiB        n = raw_input()
     6   10.551 MiB    0.000 MiB        k = []
     7   10.551 MiB    0.000 MiB        v = []
     8   10.551 MiB    0.000 MiB        print "Enter ID and M: "
     9   10.551 MiB    0.000 MiB        for i in range(0,int(n)):
    10   10.551 MiB    0.000 MiB                a, b = raw_input().split(' ')
    11   10.551 MiB    0.000 MiB                k.append(a)
    12   10.551 MiB    0.000 MiB                v.append(b)
    13
    14   10.551 MiB    0.000 MiB        d = OrderedDict(zip(k,v))
    15   10.555 MiB    0.004 MiB        sorted_items = sorted(d.items(), key=lambda (k,v):int(v), reverse=True)
    16   10.555 MiB    0.000 MiB        for i, j in sorted_items:
    17   10.555 MiB    0.000 MiB                print i, j

预期输出(我能够获得所需的输出):

3 5
26 4
22 4
16 3
20 3
1 2
11 2
7 1

此代码对于更高的输入或更高的数字是否无效? 从分析中,我可以看到只有较少的内存使用,但对于该特定测试用例,我可以看到内存利用率超过 16MB。谁能告诉我我哪里做错了。是我的方法错了还是心流错了?你能告诉我为什么我无法按预期获得输出吗?提前谢谢。任何帮助将不胜感激。

我正在写评论,但它太长了,所以我想我不妨将其升级为答案。

首先,profile装饰器本身就使用了相当多的内存。如您所见:

from memory_profiler import profile
@profile
def foo():
    pass

我得到

Line #    Mem usage    Increment   Line Contents
================================================
    2     28.5 MiB      0.0 MiB   @profile
    3                             def foo():
    4     28.5 MiB      0.0 MiB       pass

你的数字可能会有所不同(我在IDE中运行Python 3),但你的函数基本上是一样的。几乎所有内存使用量都来自@profile行 (10.520 MiB),函数添加的内容(请参阅增量列)微不足道 (0.36 MiB)。

结果是,

从外观上看,您应该没有任何问题(如果您发布的内容已经是您的整个代码,我想确实如此)。我不知道什么测试用例可以给你Memory Limit Exceeded.我们真的需要知道该测试用例是什么来调查问题。

也就是说,一项改进可以使代码更高效,尤其是对于大量输入。不需要生成中间列表(k和代码中的v)。直接写到字典:

d = OrderedDict()
for i in range(int(n)):  # Note you don't need range(0, x); just range(x)
    a, b = raw_input().split()  # No need for an argument to split, either
    d[a] = b

更好的是,您可以避免for循环并使用更高效的生成器表达式:

d = OrderedDict(raw_input().split() for _ in range(int(n)))

生成器表达式是形式(foo something_like_a_for_loop)的表达式(此处为正式描述);如果它是函数的唯一参数,则可以省略周围的括号。它在很多方面都像一个列表:你可以使用for迭代它,你可以使用list从中获取一个列表,你可以在需要迭代器时使用它。但是,当列表很长时,它比等效列表占用的空间要少得多。(但也存在差异:一个 gen expr 只能迭代一次,不能被索引并且没有len,等等。您可以在此处阅读有关它的更多信息。

您还可以进行其他小改进。全部纳入下面的重写中

def test_1():
    n = int(raw_input('Enter the number: '))
    d = OrderedDict(raw_input().split() for _ in range(n))
    sorted_items = sorted(d.items(), key=lambda k_v: int(k_v[1]), reverse=True)
    for i, j in sorted_items:
        print i, j

最新更新