python-重新加载时无法访问gc()

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 ###################

我有以下代码,另存为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
    #########################################
    def userInput(self):
        a = 1
g = GUI()
g.set_func()
print gc.collect()
print gc.garbage
这是输出:

我有两个问题:

  • 为什么gc.collect()在第一次导入时不报告不可访问?相反,它只在重新加载()时报告不可访问

  • 有没有快速的方法来修复这个函数映射循环引用,即self.functions[100]=self.userInput?因为我以前的项目有很多函数映射循环引用,我正在寻找一种快速的方法/一行代码来更改这些代码。目前,我所做的是在最后为所有这些函数“delg.functions”

  • 重新加载的本质是重新执行模块。新的定义取代了旧的定义,因此无法访问旧的值。相比之下,在第一次导入时,没有被替代的定义,因此自然没有什么是不可访问的
  • 一种方法是将
    函数
    对象作为参数传递给
    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
    可能会中断允许垃圾收集器收集它们的循环。