2013-05-02 15 views
5

假設我有可能消耗的內存相當一些非常大的Python類。這個類有一些方法,負責清理一些東西在翻譯時退出,並獲取與atexit對模塊註冊:在Python中使用atexit註冊實例方法有什麼意義?

import atexit 
import os 

class ReallyBigClass(object): 
    def __init__(self, cache_file): 
     self.cache_file = open(cache_file) 
     self.data = <some large chunk of data> 
     atexit.register(self.cleanup) 

    <insert other methods for manipulating self.data> 

    def cleanup(self): 
     os.remove(self.cache_file) 

這個類的各種實例可能來來去去,整個程序的壽命。我的問題是:

是使用atexit如果安全我,說,del我所有的其他的實例引用註冊實例方法?換句話說,atexit.register()是否像傳統綁定一樣增加引用計數器?如果是這樣,那麼現在整個類實例是否必須在內存中閒逛並等到退出,因爲它的一個方法已經用atexit註冊了,或者實例的一部分可以被垃圾回收?在類似這樣的臨時類實例的出口處構造這種清理的首選方式是什麼,以便垃圾收集可以有效地發生?

回答

7

註冊的實例方法與atexit使得整個類實例持續到解釋退出。解決方法是將課程中登記的所有功能與atexit分開。然後這些實例可以被成功地垃圾收集。例如,

import atexit 
import os 
import gc 
import random 

class BigClass1(object): 
    """atexit function tied to instance method""" 
    def __init__(self, cache_filename): 
     self.cache_filename = cache_filename 
     self.cache_file = open(cache_filename, 'wb') 
     self.data = [random.random() for i in range(10000000)] 
     atexit.register(self.cleanup) 

    def cleanup(self): 
     self.cache_file.close() 
     os.remove(self.cache_filename) 

class BigClass2(object): 
    def __init__(self, cache_filename): 
     """atexit function decoupled from instance""" 
     self.cache_filename = cache_filename 
     cache_file = open(cache_filename, 'wb') 
     self.cache_file = cache_file 
     self.data = [random.random() for i in range(10000000)] 

     def cleanup(): 
      cache_file.close() 
      os.remove(cache_filename) 

     atexit.register(cleanup) 

if __name__ == "__main__": 
    import pdb; pdb.set_trace() 

    big_data1 = BigClass1('cache_file1') 
    del big_data1 
    gc.collect() 

    big_data2 = BigClass2('cache_file2') 
    del big_data2 
    gc.collect() 

由線步進通過這條線和監視過程存儲器示出了由big_data1消耗存儲器一直保持到解析器退出而big_data2是成功del後收集垃圾。單獨運行每個測試用例(註釋另一個測試用例)提供了相同的結果。

0

我爲atexit實施想象力是象下面這樣:

try: 
    # Your whole program 
finally: 
    if sys.exitfunc: 
     sys.exitfunc() 

和模塊atexit只安裝sys.exitfunc到自己的回調。因此,由於解釋器關閉導致的任何清理,您無需擔心任何消失的對象。

注1:它沒有指定會發生什麼,如果sys.exitfunc將調用sys.exit(EXIT_CODE)但對我來說「EXIT_CODE」返回

注2:atexit執行所有註冊的功能依次捕獲所有異常,所以它也隱藏sys.exit執行(因爲它只是提高SystemExit例外)

相關問題