【问题标题】:Numpy and matplotlib garbage collectionNumpy 和 matplotlib 垃圾回收
【发布时间】:2015-12-27 00:01:39
【问题描述】:

我有一个 python 脚本,它对不同的参数(QK)进行许多模拟,绘制结果并将其存储到磁盘。

每组参数 (Q,K) 都会生成一个 200x200x80 数据点的 3D 体积网格,这需要大约 100 MB 的数据。然后逐层绘制该体积网格的一部分,生成约 60 张图像。

问题是python在这个过程中显然没有释放内存。我不确定内存泄漏在哪里,或者控制 python 如何决定释放哪些对象的规则是什么。我也不确定numpy数组或matplotlib图形对象中的内存是否丢失。

  1. 是否有一种简单的方法来分析 python 中哪些对象持久存在内存中,哪些对象被自动释放?
  2. 是否有一种方法可以强制 python 释放所有在特定循环周期或特定函数调用中创建的数组和图形对象

相关部分代码在这里(不过,它不会运行......大部分模拟代码包括ctypesC++/python接口,因为太复杂,所以省略了):

import numpy as np
import matplotlib.pyplot as plt
import ProbeParticle as PP # this is my C++/Python simulation library, take it as blackbox

def relaxedScan3D( xTips, yTips, zTips ):
    ntips = len(zTips); 
    print " zTips : ",zTips
    rTips = np.zeros((ntips,3)) # is this array deallocated when exiting the function?
    rs    = np.zeros((ntips,3)) # and this?
    fs    = np.zeros((ntips,3)) # and this?
    rTips[:,0] = 1.0
    rTips[:,1] = 1.0
    rTips[:,2] = zTips 
    fzs    = np.zeros(( len(zTips), len(yTips ), len(xTips ) )); # and this?
    for ix,x in enumerate( xTips  ):
        print "relax ix:", ix
        rTips[:,0] = x
        for iy,y in enumerate( yTips  ):
            rTips[:,1] = y
            itrav = PP.relaxTipStroke( rTips, rs, fs ) / float( len(zTips) )
            fzs[:,iy,ix] = fs[:,2].copy()
    return fzs


def plotImages( prefix, F, slices ):
    for ii,i in enumerate(slices):
        print " plotting ", i
        plt.figure( figsize=( 10,10 ) ) # Is this figure deallocated when exiting the function ?
        plt.imshow( F[i], origin='image', interpolation=PP.params['imageInterpolation'], cmap=PP.params['colorscale'], extent=extent )
        z = zTips[i] - PP.params['moleculeShift' ][2]
        plt.colorbar();
        plt.xlabel(r' Tip_x $\AA$')
        plt.ylabel(r' Tip_y $\AA$')
        plt.title( r"Tip_z = %2.2f $\AA$" %z  )
        plt.savefig( prefix+'_%3.3i.png' %i, bbox_inches='tight' )

Ks = [ 0.125, 0.25, 0.5, 1.0 ]
Qs = [ -0.4, -0.3, -0.2, -0.1, 0.0, +0.1, +0.2, +0.3, +0.4 ]

for iq,Q in enumerate( Qs ):
    FF = FFLJ + FFel * Q
    PP.setFF_Pointer( FF )
    for ik,K in enumerate( Ks ):
        dirname = "Q%1.2fK%1.2f" %(Q,K)
        os.makedirs( dirname )
        PP.setTip( kSpring = np.array((K,K,0.0))/-PP.eVA_Nm )
        fzs = relaxedScan3D( xTips, yTips, zTips ) # is memory of "fzs" recycled or does it consume more memory each cycle of the loop ?
        PP.saveXSF( dirname+'/OutFz.xsf', headScan, lvecScan, fzs )
        dfs = PP.Fz2df( fzs, dz = dz, k0 = PP.params['kCantilever'], f0=PP.params['f0Cantilever'], n=int(PP.params['Amplitude']/dz) ) # is memory of "dfs" recycled?
        plotImages( dirname+"/df", dfs, slices = range( 0, len(dfs) ) )

【问题讨论】:

  • 问题是你把所有的数字都保留在周围并打开。如果要使用pyplot 状态机接口,则每次都需要显式关闭图形。否则,它们将被保留,以便在您调用 plt.show 时显示它们。作为快速修复,请在plt.savefig 之后致电plt.close()
  • Ahoj Prokope,尝试另一种方法来利用 matplotlib >>> [Interactive Applications Using Matplotlib; Benjamin V. Root, (2015)]
  • 作为开胃菜,不妨看看嵌入式MVC-live-matplotlib-GUI样例>>>stackoverflow.com/a/25769600/3666197
  • 对于内存管理,请阅读有关可用于 python 的内存分析器的详细信息。顺便说一句,python 不仅不愿释放内存,更不愿将其返回给 O/S。分布式进程可能会让您在 HPC 场景中的主线程/进程中不受此影响。然而,大多数指示的问题都可以通过实时 GUI 或使用哑力 .clf() / .close() 方法解决(防止)。

标签: python numpy matplotlib


【解决方案1】:

尝试重复使用你的身材:

plt.figure(0, figsize=(10, 10))
plt.clf() #clears figure

或保存后关闭图:

...
plt.savefig(...)
plt.close()

【讨论】:

  • 啊哈,谢谢,看来plt.close() 不再存在内存泄漏。不过,最好能清楚地了解规则是什么以及如何分析这些泄漏。
  • 没有泄漏,如果你使用 pyplot plt.figure 每次都会给你一个新的数字,旧的仍然可以通过调用plt.figure(n) 获得,其中 n 是数字的编号。
猜你喜欢
  • 2015-11-13
  • 1970-01-01
  • 2011-08-01
  • 2012-02-19
  • 1970-01-01
  • 1970-01-01
  • 2014-07-21
  • 1970-01-01
相关资源
最近更新 更多