Python:记录垃圾收集器

3 投票
2 回答
4725 浏览
提问于 2025-04-17 06:34

我有一个用Python写的应用程序,运行时有些卡顿。我想把垃圾回收器的事件(特别是它什么时候被调用)记录到我的日志里。这样可以吗?

谢谢。

2 个回答

1

Python(至少是CPython版本2.x)使用引用计数来实现它的垃圾回收机制(参考为什么Java和Python的垃圾回收方法不同?),所以它的工作方式和Java不太一样,不是通过“调用”来完成的。

引用计数的意思是,每当你创建一个指向某个对象的新引用时,计数器就会加1;而每当这个引用失效(比如超出作用域、被重新赋值等),计数器就会减1。当计数器减到0时,这个对象占用的内存就会被释放。

所以Python给你问题的解决方案是重写对象的__del__方法:

class test:
    def __del__(self):
         #self is about to be freed, do what ever you want 
         pass

编辑: 根据上面的链接,还有一个机制会定期运行:

CPython(引用计数并不是Python本身的一部分,而是其C语言实现的一部分)会通过一个单独的垃圾回收程序来处理循环引用,这个程序会定期运行……

但这个机制只在出现循环引用的情况下才会涉及。

编辑2: 正如评论中提到的,以及在这里提到的,__del__并不是最安全的解决方案。这里有一种更好的方法来实现类似的效果:

import weakref

class test:
    pass

t = test()

def prepare_cb(obj):
  #save information about the obj
  uid = id(obj)

  def do_some_logging(weak):
     print "Object %s cleaned up" % uid

  return do_some_logging

weak = weakref.ref(t, prepare_cb(t))

del t
6

http://docs.python.org/library/gc.html#gc.set_debug

你可以设置一些标志,但这些信息会写到错误输出中。

可用的标志有:

gc.DEBUG_STATS
gc.DEBUG_COLLECTABLE
gc.DEBUG_UNCOLLECTABLE
gc.DEBUG_INSTANCES
gc.DEBUG_OBJECTS
gc.DEBUG_SAVEALL
gc.DEBUG_LEAK

另外

如果你在关注代码的性能,可能想要分析一下你的代码,看看有没有耗时的循环或者函数调用。你可以使用 cProfile 或者 hotshot 来进行分析。更多信息可以查看 http://docs.python.org/library/profile.html

撰写回答