python-重新加载时无法访问gc()
我有以下代码,另存为so.py:python-重新加载时无法访问gc(),python,python-2.7,garbage-collection,circular-reference,Python,Python 2.7,Garbage Collection,Circular Reference,我有以下代码,另存为so.py: import gc gc.set_debug(gc.DEBUG_STATS|gc.DEBUG_LEAK) class GUI(): ######################################### def set_func(self): self.functions = {} self.functions[100] = self.userInput ###################
import gc
gc.set_debug(gc.DEBUG_STATS|gc.DEBUG_LEAK)
class GUI():
#########################################
def set_func(self):
self.functions = {}
self.functions[100] = self.userInput
#########################################
def userInput(self):
a = 1
g = GUI()
g.set_func()
print gc.collect()
print gc.garbage
这是输出:
我有两个问题:
函数
对象作为参数传递给set_func
,而不将其指定为实例属性。这将打破循环,同时仍然允许您将函数
对象传递到需要的位置的引用,所以模块和所有其他对象都被它引用,所以它们都是活动的,垃圾收集器也没有收集任何内容
当您reload(so)
时,发生的是模块被重新执行,覆盖所有以前的引用,因此现在旧值不再有任何引用
您在以下情况下有一个参考循环:
self.functions[100] = self.userInput
由于self.userInput
是一个绑定方法,因此它引用了self
。因此,现在self
引用了functions
字典,该字典引用了userInput
绑定方法,该方法引用了self
,而gc
将收集这些对象
self.functions
字典的,根据不同的选项可能是可行的
打破这种循环最简单的方法就是不创建self.functions
属性,而是显式地传递字典
如果self.functions
仅引用绑定的方法,则可以存储方法的名称,而不是方法本身:
self.functions[100] = self.userInput.__name__
然后您可以调用该方法执行以下操作:
getattr(self, self.functions[100])()
或者你可以:
from operator import methodcaller
call_method = methodcaller(self.functions[100])
call_method(self) # calls self.userInput()
delg.functions
”是什么意思。你说的是哪些函数
还有,这真的是个问题吗?您是否遇到了真正的内存泄漏
请注意,垃圾收集器将对象报告为不可访问,而不是不可收集。这意味着即使对象是引用循环的一部分,也会释放它们。因此,不应发生内存泄漏
事实上,添加del g.functions
是没有用的,因为对象无论如何都会被释放,所以一行修复就是简单地删除所有那些del
语句,因为它们根本不做任何事情
它们被放入
gc.garbage
的事实是因为gc.DEBUG\u LEAK
意味着标记gc.DEBUG\u SAVEALL
,这使得收集器将所有无法访问的对象放入垃圾
,而不仅仅是无法收集的对象。1。只有当我把这一行“self.functions[100]=self.userInput”放进去时,才会出现无法访问的情况。我不明白原因。2.我知道实例属性将导致这个循环引用,但我正在寻找全局/快速的方法来修复它,同时仍将其保留为实例属性。类似于sys.exc_clear()solution。如果您坚定地希望实例保留指向映射的指针,并且坚定地希望映射包含指向实例的指针,那么您需要循环引用。我现在很困惑,“引用循环”会导致任何问题吗?或者它只是一种风格上的优势?它会导致内存泄漏,因为Python GC不能保证找到并释放循环。如果在循环变为空闲之前撤消循环(即当不再需要其GUI
对象时放弃功能
),则泄漏已修复。无法访问的对象将被释放。无法收集的对象不会被释放(请参见)。在本例中,OP提供的是无内存泄漏。输出仅仅意味着GC将释放这些对象(如果它们是可访问的,那么它们的引用将是活动的)。如果输出是gc:done,8个不可访问,8个不可收集,xxxx已过
,则会出现问题,但本例中的情况并非如此。如果GUI
有一个\uuu del\uuu
方法,就会有这样的输出和内存泄漏。你说不可访问不是内存泄漏的原因,但为什么我必须修复不可访问的引用周期?“del g.functions”并不是无用的,它确实避免了重载()时无法访问的功能@林果皞 “不可访问”只是意味着垃圾收集器将取消分配它们。这意味着它们无法通过任何引用访问(在其周期之外)。内存泄漏涉及无法收集的对象,垃圾收集器不会释放这些对象。如果你有一个内存泄漏问题,你可能应该提出一个新的问题。请注意,如果您的某些对象实现了\uuu del\uu
方法,则它们可能无法收集。在这种情况下,使用delg.functions
可能会中断允许垃圾收集器收集它们的循环。