这是我为我的一位同事准备的非常详细的解释。我认为它在这里也会很有帮助。不过请耐心等待,我会在最后讲到你遇到的真正问题。只作为预告,它涉及额外引用了你的Line2D对象。
注意:在我们深入讨论之前还有一个要点。如果您正在使用IPython进行测试,则IPython会保留自己的引用,其中并非所有引用都是弱引用。因此,在IPython中测试垃圾回收无效。它只会让事情更加混乱。
好的,让我们开始吧。每个matplotlib对象(Figure、Axes等)都通过各种属性提供对其子艺术家的访问。以下示例变得相当长,但应该很有启示性。
我们首先创建一个Figure对象,然后将一个Axes对象添加到该图形中。请注意,ax和fig.axes [0]是同一个对象(相同的id())。
>>> #Create a figure
>>> fig = plt.figure()
>>> fig.axes
[]
>>> #Add an axes object
>>> ax = fig.add_subplot(1,1,1)
>>> #The object in ax is the same as the object in fig.axes[0], which is
>>> # a list of axes objects attached to fig
>>> print ax
Axes(0.125,0.1;0.775x0.8)
>>> print fig.axes[0]
Axes(0.125,0.1;0.775x0.8) #Same as "print ax"
>>> id(ax), id(fig.axes[0])
(212603664, 212603664) #Same ids => same objects
这也适用于坐标轴对象中的线条:
>>> #Add a line to ax
>>> lines = ax.plot(np.arange(1000))
>>> #Lines and ax.lines contain the same line2D instances
>>> 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)
>>> #Same ID => same object
>>> 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 中删除元素将从当前绘图中删除该线。 因此:
>>> #THIS DOES NOTHING:
>>> lines.pop(0)
>>> #THIS REMOVES THE FIRST LINE:
>>> ax.lines.pop(0)
因此,如果您运行第二行代码,您将从当前图中删除包含在ax.lines[0]中的Line2D对象,并且它将不存在。请注意,这也可以通过ax.lines.remove()完成,这意味着您可以将Line2D实例保存在变量中,然后将其传递给ax.lines.remove()以删除该线条,就像这样:
>>> #Create a new line
>>> lines.append(ax.plot(np.arange(1000)/2.0))
>>> ax.lines
[<matplotlib.lines.Line2D object at 0xce84bd0>, <matplotlib.lines.Line2D object at 0xce84dx3>]

>>> #Remove that new line
>>> ax.lines.remove(lines[0])
>>> ax.lines
[<matplotlib.lines.Line2D object at 0xce84dx3>]

对于fig.axes,所有上述内容同样适用于ax.lines
现在,真正的问题是:如果我们将ax.lines[0]中包含的引用存储到一个weakref.ref对象中,然后尝试删除它,我们会发现它不会被垃圾回收:
>>> #Create weak reference to Line2D object
>>> 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>
>>> #Delete the line from the axes
>>> ax.lines.remove(wr())
>>> ax.lines
[]
>>> #Test weakref again
>>> print wr
<weakref at 0xb758af8; to 'Line2D' at 0xb757fd0>
>>> print wr()
<matplotlib.lines.Line2D at 0xb757fd0>
引用仍然有效!为什么呢?这是因为还有另一个引用指向wr中的Line2D对象。还记得lines与ax.lines没有相同的ID但包含相同的元素吗?这就是问题所在。
>>> #Print out 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.
>>> #Reinitialize lines to empty list
>>> lines = []
>>> print lines
[]
>>> print wr
<weakref at 0xb758af8; dead>
因此,这个故事想要告诉我们的道理是,要自己清洗干净。如果你期望某个东西被垃圾回收,但它没有被回收,那么很可能是你留下了一些未处理的引用。
remove()函数,可以将它们从mpl清除,然后您只需要跟踪您的引用即可。 - tacaswell