为大对象分配名称似乎会大大增加内存使用量

时间:2015-06-24 18:56:22

标签: python python-2.7 numpy memory-management memory-profiling

通常,当我需要调用复杂的公式时,我将其分解为两行或更多行以使代码更易于理解。但是,在分析计算RMSE的某些代码时,我发现这样做会增加代码的内存使用量。这是一个简化的例子:

import numpy as np
import random
from memory_profiler import profile

@profile
def fun1():
    #very large datasets (~750 mb each)
    predicted = np.random.rand(100000000)
    observed = np.random.rand(100000000)
    #calculate residuals as intermediate step
    residuals = observed - predicted
    #calculate RMSE
    RMSE = np.mean(residuals **2) ** 0.5
    #delete residuals
    del residuals

@profile
def fun2():
    #same sized data
    predicted = np.random.rand(100000000)
    observed = np.random.rand(100000000)
    #same calculation, but with residuals and RMSE calculated on same line
    RMSE = np.mean((observed - predicted) ** 2) ** 0.5

if __name__ == "__main__":
    fun1()
    fun2()

输出:

Filename: memtest.py

Line #    Mem usage    Increment   Line Contents
================================================
     5     19.9 MiB      0.0 MiB   @profile
     6                             def fun1():
     7    782.8 MiB    763.0 MiB        predicted = np.random.rand(100000000)
     8   1545.8 MiB    762.9 MiB        observed = np.random.rand(100000000)
     9   2308.8 MiB    763.0 MiB        residuals = observed - predicted
    10   2308.8 MiB      0.1 MiB        RMSE = np.mean(residuals ** 2) ** 0.5
    11   1545.9 MiB   -762.9 MiB        del residuals


Filename: memtest.py

Line #    Mem usage    Increment   Line Contents
================================================
    13     20.0 MiB      0.0 MiB   @profile
    14                             def fun2():
    15    783.0 MiB    762.9 MiB        predicted = np.random.rand(100000000)
    16   1545.9 MiB    762.9 MiB        observed = np.random.rand(100000000)
    17   1545.9 MiB      0.0 MiB        RMSE = np.mean((observed - predicted) **
 2) ** 0.5

正如您所看到的,第一个函数(计算被拆分)似乎需要额外的~750 mb峰值 - 可能是residuals数组的成本。但是,这两个函数都需要创建数组 - 唯一的区别是第一个函数为它指定了一个名称。这与我对python中内存管理的工作原理的理解相反。

那么,这里发生了什么?一种想法是,这可能是memory_profiler模块的一些工件。在运行期间观察Windows任务管理器表明了类似的模式(虽然我知道这不是一个非常值得信赖的验证)。如果这是一个“真实”的影响,我对内存处理方式的误解是什么?或者,这有点特定于numpy吗?

1 个答案:

答案 0 :(得分:4)

memory_profiler的“Mem usage”列告诉您每行完成后的内存使用情况,而不是该行中的峰值内存使用情况。在您不保存residuals的版本中,该行在行完成之前被丢弃,因此它永远不会显示在探查器输出中。