【发布时间】:2016-03-05 11:58:32
【问题描述】:
我运行一个服务器,它充当团队内客户的数据处理节点。最近,我们一直在重构服务器中的遗留代码,以利用 numpy 进行一些过滤/转换作业。
由于我们必须将此数据提供给远程客户端,因此我们将 numpy 数据转换为各种形式,使用 numpy.tolist() 作为中间步骤。
每个查询都是无状态的,没有全局变量,因此在查询之间不会维护任何引用。
在一个特定步骤中,我发现了明显的内存泄漏,我一直试图通过 memory_profiler 进行追踪。此步骤涉及将大型(>4m 条目)ndarray 浮点数转换为 python 列表。我第一次发出查询时,tolist() 调用分配了 120m 的内存,然后在我释放 numpy 数组时释放了 31m。第二次(以及随后的时间)我发出相同的查询,分配/解除分配是 31m。我发出的每个不同查询都有相同的模式,但绝对值不同。
为了便于说明,我已经拆散了我的代码,并强制输入了一些 del 命令。下面的输出来自 memory_profiler.profile
第一期查询:
Line # Mem usage Increment Line Contents
================================================
865 296.6 MiB 0.0 MiB p = ikeyData[1]['value']
866 417.2 MiB 120.6 MiB newArr = p.tolist()
867 417.2 MiB 0.0 MiB del p
868 385.6 MiB -31.6 MiB del ikeyData[1]['value']
869 385.6 MiB 0.0 MiB ikeyData[1]['value'] = newArr
同一查询的第二个(和后续)实例:
Line # Mem usage Increment Line Contents
================================================
865 494.7 MiB 0.0 MiB p = ikeyData[1]['value']
866 526.3 MiB 31.6 MiB newArr = p.tolist()
867 526.3 MiB 0.0 MiB del p
868 494.7 MiB -31.6 MiB del ikeyData[1]['value']
869 494.7 MiB 0.0 MiB ikeyData[1]['value'] = newArr
您可以想象,在一个具有高度可变查询的长期运行过程中,这些分配会不断累积,迫使我们定期反弹服务器。
有人对这里可能发生的事情有想法吗?
【问题讨论】:
-
首先想到的是检查numpy的源码。
-
如果只有第一次运行会产生过多的分配 - 它们是如何“建立”的?
-
@ivan_pozdeev 每个唯一查询都会产生不同的过度初始分配。我们在某一天有数千个独特的查询。
-
正如linked question 和Mike's answer 所说,您应该检查Python 的GC 而不是原始内存占用。后者只有在前者什么也没显示的情况下才有用 - 然后发生过多的内存碎片,内存管理设施出现故障,或者
numpy正在泄漏(两者都极不可能)。没有minimal reproducible example,我们真的无话可说。
标签: python python-2.7 numpy