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

林果皞*_*林果皞 2 python garbage-collection circular-reference python-2.7

我有这个代码,另存为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
Run Code Online (Sandbox Code Playgroud)

这是输出: 在此输入图像描述

我有两个问题:

  1. 为什么gc.collect()在第一次导入时不报告无法访问?相反,它仅在reload()时报告无法访问.

  2. 有没有快速的方法来修复这个函数映射循环引用,即self.functions [100] = self.userInput?因为我的旧项目有很多这个函数映射循环引用,我正在寻找一个快速的方法/一行来改变这些代码.目前我所做的是最后所有这些功能的"del g.functions".

Bak*_*riu 5

  1. 第一次导入模块时,没有收集任何内容,因为你有一个对so模块的引用,并且所有其他对象都被它引用,所以它们都是活动的,垃圾收集器没有任何东西可以收集.

    当你reload(so)发生的事情是重新执行该模块,覆盖所有以前的引用,因此现在旧的值不再有任何引用.

    这样做有一个参考周期:

     self.functions[100] = self.userInput
    
    Run Code Online (Sandbox Code Playgroud)

    因为它self.userInput是一个绑定方法,它有一个参考self.所以现在self已经到一个参考functions其具有的一个参考字典userInput 必然具有参照方法selfgc将收集的对象.

  2. 这取决于你想要做什么.从您的代码不清楚您如何使用该self.functions字典,并取决于不同的选项可能是可行的.

    打破循环的最简单方法是简单地创建self.functions属性,而是明确地传递字典.

    如果self.functions只引用绑定方法,则可以存储方法的名称而不是方法本身:

    self.functions[100] = self.userInput.__name__
    
    Run Code Online (Sandbox Code Playgroud)

    然后你可以调用方法:

    getattr(self, self.functions[100])()
    
    Run Code Online (Sandbox Code Playgroud)

    或者你可以这样做:

    from operator import methodcaller
    call_method = methodcaller(self.functions[100])
    call_method(self)   # calls self.userInput()
    
    Run Code Online (Sandbox Code Playgroud)

我真的不明白你的意思是"目前我所做的就是最后del g.functions所有这些功能." 你在谈论哪些功能?

这也是一个问题吗?您是否遇到过真正的内存泄漏?

请注意,垃圾收集器将对象报告为无法访问而不是无法收集.这意味着即使它们是参考循环的一部分,也会释放这些对象.所以不应该发生内存泄漏.

事实上,添加del g.functions无用的,因为无论如何都会释放对象,所以一行修复就是简单地删除所有这些del语句,因为它们根本不做任何事情.

它们被放入的事实gc.garbage是因为gc.DEBUG_LEAK暗示了GC.DEBUG_SAVEALL使收集器将所有无法到达的对象放入garbage而不仅仅是无法收集的对象的标志.