嘿大家
我发现了一个问题。 只需启动代码并查看内存即可。 然后删除“%matplotlib inline”并再次启动。
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.ticker
%matplotlib inline
import os
import sys
import StringIO
import urllib, base64
from matplotlib import rcParams
rcParams['figure.figsize'] = (24, 6)
rcParams['figure.dpi'] = 150
OUTPUT_FILENAME = "Asd"
def printHTML(html):
with open(OUTPUT_FILENAME, "a") as outputFile: outputFile.write(html if type(html) == str else html.encode('utf8') )
def friendlyPlot():
figure = plt.Figure()
ax = plt.subplot2grid((1,2), (0,0))
ax.plot( range(1000), range(1000) )
#plt.show()
fig = plt.gcf()
imgdata = StringIO.StringIO()
fig.savefig(imgdata, format='png')
imgdata.seek(0) # rewind the data
image = imgdata.buf.encode('base64').replace('\n', '')
printHTML('<img src="data:image/png;base64,{0}" /><br />'.format(image))
plt.close('all')
imgdata.close()
open(OUTPUT_FILENAME, 'w').close()
for i in range(500):
friendlyPlot()
我也遇到了这个错误,有没有办法获得没有内存泄漏的内联图? 我不想为每个图启动单独的过程,因为数组很大。
当内存使用量增加时,您能检查一下吗:
len(IPython.kernel.zmq.pylab.backend_inline.show._to_draw)
那是存储数字的列表。 他们应该只是暂时存在,但也许他们没有被清除就正在建立。
len(IPython.kernel.zmq.pylab.backend_inline.show._to_draw)= 0
顺便说一句,我正在使用.plot()
方法绘制熊猫数据帧。
好的,对于那个理论来说就这么多了。
大熊猫也可能会在内部围绕地块保留一些数据。 不过,原始报告不涉及熊猫。
每个额外的图看起来要增加多少内存?
好的,这似乎是我的情况,我使用的是熊猫0.16.0,但问题已在master中修复:
十分感谢。 由于原始报告不涉及熊猫,因此不公开。
这可以更简单地复制:
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.ticker
%matplotlib inline
import os
import sys
import StringIO
import urllib, base64
from matplotlib import rcParams
rcParams['figure.figsize'] = (24, 6)
rcParams['figure.dpi'] = 150
def friendlyPlot():
fig, ax = plt.subplots()
ax.plot(range(1000))
fig.savefig('tmp.png')
plt.close('all')
for i in range(500):
friendlyPlot()
这不会泄漏内存,所以它在IPython方面而不是pyplot方面(我认为)。
import matplotlib
matplotlib.use('agg')
import matplotlib.pyplot as plt
import matplotlib.ticker
import os
import sys
import StringIO
import urllib, base64
from matplotlib import rcParams
rcParams['figure.figsize'] = (24, 6)
rcParams['figure.dpi'] = 150
def friendlyPlot():
fig, ax = plt.subplots()
ax.plot(range(1000))
fig.savefig('tmp.png')
plt.close('all')
for i in range(500):
friendlyPlot()
@tacaswell在您的测试代码中,Windows 7上的IPython消耗了大约1.7GB,此后未释放。 以稍高的迭代次数运行会导致内存错误。 因此,这仍然是一个问题。
@asteppke第一个或第二个块?
@tacaswell第一个测试代码( %matplotlib inline
)的内存消耗将达到1.7GB。 相反,使用第二部分( matplotlib.use('agg')
)时,内存使用量仅在50MB和100MB之间振荡。
这两个测试都是使用Python 3.4和IPython Notebook版本4.0.5执行的。
我已经玩了更多。 我注意到,如果我在@tacaswell的示例中重新运行for循环几次,则内存使用不会增加-这似乎与您在单个单元格中创建的数量很重要。 IPython当然会保留该单元格中为内联后端生成的所有图形的列表,但是在运行该单元格后,肯定会清除该列表,即使执行gc.collect()
也不会使内存使用率下降。
我们的代码可能与matplotlib中的某些东西进行严重的交互吗? 我以为_pylab_helpers.Gcf
看起来很可能,但似乎没有保留任何东西。
我试图抓住其中一个数字的引用,并在其上调用gc.get_referrers()
; 除了我在user_ns中拥有的引用以外,所有其他引用都看起来像mpl对象-大概其中许多处于引用循环中。 什么对象最有可能是其他内容不恰当地保留引用?
我将其放入里程碑“愿望清单”中。 我们想修复它,但是目前我们不确定如何在识别该错误方面取得进一步的进展,我认为不值得为此保留版本。
任何可以进步的人都会得到布朗尼积分。 还蛋糕。
并不是真正的进步,但是内存似乎在内核内部的某个地方丢失了。 在循环后或循环内调用gc.collect()
都没有帮助,并且summary.print_(summary.summarize(muppy.get_objects()))
找不到任何泄漏的内存。 也不会将所有_N
和_iN
为None
帮助。 真的很神秘。
我也想知道它是否正在创建无法收集的对象,但是当没有其他引用时,它们应该以gc.garbage
结尾,并且当我看到它用尽RAM负载时,它仍然为空。
我认为知道这些事情的人将不得不使用C级工具来跟踪未释放的内存。 没有证据表明我们可以找到任何地方保留额外的Python对象。
我将第二次对此问题进行修复,将不胜感激。
我们知道,但是目前还没有人找出导致该错误的原因。
+1
+1
顺便说一句,我仍然不时在最新的matplotlib,熊猫,jupyter和ipython上遇到这个问题。 如果有人知道可以帮助解决此多进程通信问题的调试器,请告诉我。
可能与浏览器缓存机制有关吗?
好主意,但我不这么认为。 这是IPython占用额外内存的过程,而不是浏览器,并且
@tacaswell的复制不涉及将情节发送到浏览器。
嗨,我相信我已经找到了罪魁祸首的一部分,并且是一种可以(但不是完全)减轻这一问题的方法!
滚动浏览ipykernel/pylab/backend_inline.py
代码后,我直觉交互模式会大量存储“ plot-things”,尽管我并不完全了解它,所以我无法查明确切的原因确定无疑。
这是验证此代码的代码(基于上面的@tacaswell的片段),对于尝试实施此修复程序的任何人都非常有用。
初始化:
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.ticker
%matplotlib inline
matplotlib.rcParams['figure.figsize'] = (24, 6)
matplotlib.rcParams['figure.dpi'] = 150
from resource import getrusage
from resource import RUSAGE_SELF
def friendlyPlot():
fig, ax = plt.subplots()
ax.plot(range(1000))
fig.savefig('tmp.png')
plt.close('all')
实际测试:
print("before any: {:7d} kB".format(getrusage(RUSAGE_SELF).ru_maxrss))
friendlyPlot()
print("before loop: {:7d} kB".format(getrusage(RUSAGE_SELF).ru_maxrss))
for i in range(50):
friendlyPlot()
print("after loop: {:7d} kB".format(getrusage(RUSAGE_SELF).ru_maxrss))
import gc ; gc.collect(2)
print("after gc: {:7d} kB".format(getrusage(RUSAGE_SELF).ru_maxrss))
运行它的50次循环迭代,我得到:
before any: 87708 kB
before loop: 106772 kB
after loop: 786668 kB
after gc: 786668 kB
将其运行200次循环,得到:
before any: 87708 kB
before loop: 100492 kB
after loop: 2824316 kB
after gc: 2824540 kB
这显示了随着迭代内存的线性增长。
现在解决问题/解决方法:在测试代码片段之前调用matplotlib.interactive(False)
,然后运行它。
经过50次迭代:
before any: 87048 kB
before loop: 104992 kB
after loop: 241604 kB
after gc: 241604 kB
并进行200次迭代:
before any: 87536 kB
before loop: 103104 kB
after loop: 239276 kB
after gc: 239276 kB
这证实只剩下恒定的增量(与迭代无关)。
使用这些数字,我可以粗略估计每次迭代的泄漏大小:
(786668-(241604 - 104992))/50 = 13001.12
(2824316-(241604 - 104992))/200 = 13438.52
对于循环的单次迭代,我得到13560
。 因此,无论是原始(> 3MB)还是png压缩(54KB),每次迭代的泄漏
而且,奇怪的是,在同一单元中重复运行小规模测试(仅几次迭代)而没有重新启动内核的一致性要差得多,我无法理解这一点或确定模式。
我希望对内部结构有更多了解的人可以从这里开始学习,因为我现在没有时间和知识来深入研究它。
有用
最有用的评论
我将第二次对此问题进行修复,将不胜感激。