这是我为我的一位同事输入的很长的解释。我认为这也会有所帮助。不过要有耐心。我要解决您即将面临的真正问题。就像一个预告片一样,这是对您的Line2D
对象周围悬挂的额外引用的问题。
警告:在我们深入研究之前,请注意另一点。如果您正在使用IPython进行测试,则IPython会保留自己的引用,但并非所有引用都是弱引用。因此,无法在IPython中测试垃圾回收。这只会使事情变得混乱。
好的,我们开始。每个matplotlib
对象(Figure
,Axes
等)都可以通过各种属性访问其子艺术家。以下示例变得很长,但应该很有启发。
我们首先创建一个Figure
对象,然后Axes
向该图中添加一个对象。请注意,ax
和fig.axes[0]
是相同的对象(相同id()
)。
>>>
>>> fig = plt.figure()
>>> fig.axes
[]
>>>
>>> ax = fig.add_subplot(1,1,1)
>>>
>>>
>>> print ax
Axes(0.125,0.1;0.775x0.8)
>>> print fig.axes[0]
Axes(0.125,0.1;0.775x0.8)
>>> id(ax), id(fig.axes[0])
(212603664, 212603664)
这也扩展到轴对象中的线:
>>>
>>> lines = ax.plot(np.arange(1000))
>>>
>>> print lines
[<matplotlib.lines.Line2D object at 0xce84bd0>]
>>> print ax.lines
[<matplotlib.lines.Line2D object at 0xce84bd0>]
>>> print lines[0]
Line2D(_line0)
>>> print ax.lines[0]
Line2D(_line0)
>>>
>>> id(lines[0]), id(ax.lines[0])
(216550352, 216550352)
如果plt.show()
使用上面的操作进行调用,您将看到一个包含一组轴和一行的图形:
现在,虽然我们已经看到的内容lines
和ax.lines
是一样的,但要注意的是在引用的对象是非常重要的lines
变量是不一样的尊崇对象ax.lines
为可通过以下所见:
>>> id(lines), id(ax.lines)
(212754584, 211335288)
结果,从中删除元素lines
不会对当前绘图产生任何影响,但从中删除元素ax.lines
会从当前绘图中删除该线。所以:
>>>
>>> lines.pop(0)
>>>
>>> ax.lines.pop(0)
因此,如果要运行第二行代码,则应从当前图中删除其中Line2D
包含的对象,该对象ax.lines[0]
将消失。请注意,这也可以通过以下方式完成ax.lines.remove()
:将Line2D
实例保存在变量中,然后将其传递ax.lines.remove()
给该行以删除该行,如下所示:
>>>
>>> lines.append(ax.plot(np.arange(1000)/2.0))
>>> ax.lines
[<matplotlib.lines.Line2D object at 0xce84bd0>, <matplotlib.lines.Line2D object at 0xce84dx3>]
>>>
>>> ax.lines.remove(lines[0])
>>> ax.lines
[<matplotlib.lines.Line2D object at 0xce84dx3>]
以上所有功能都fig.axes
适用于ax.lines
现在,真正的问题在这里。如果我们将其中包含的引用存储ax.lines[0]
到一个weakref.ref
对象中,然后尝试将其删除,则会注意到该引用不会被垃圾收集:
>>>
>>> from weakref import ref
>>> wr = ref(ax.lines[0])
>>> print wr
<weakref at 0xb758af8; to 'Line2D' at 0xb757fd0>
>>> print wr()
<matplotlib.lines.Line2D at 0xb757fd0>
>>>
>>> ax.lines.remove(wr())
>>> ax.lines
[]
>>>
>>> print wr
<weakref at 0xb758af8; to 'Line2D' at 0xb757fd0>
>>> print wr()
<matplotlib.lines.Line2D at 0xb757fd0>
参考仍然有效!为什么?这是因为该引用所指向的Line2D
对象还有另一个引用wr
。还记得lines
ID如何不具有相同的IDax.lines
却包含相同的元素吗?好吧,这就是问题所在。
>>>
>>> print lines
[<matplotlib.lines.Line2D object at 0xce84bd0>, <matplotlib.lines.Line2D object at 0xce84dx3>]
To fix this problem, we simply need to delete `lines`, empty it, or let it go out of scope.
>>>
>>> lines = []
>>> print lines
[]
>>> print wr
<weakref at 0xb758af8; dead>
因此,故事的寓意是,要自己清理。如果您希望某些东西被垃圾回收,但实际上却不是,那么您可能会将参考留在某个地方。