Python: logging the garbage collector

2019-07-20 04:05发布

问题:

I have a python application that has some performance hiccups. I want to add the garbage collector's events (especially, when does it get called) to my logs. Is it possible?

thanks.

回答1:

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

You can set the Flags, but they get written to stderr.

Available flags are

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

ALSO

When you are dealing with performance, you might wish to profile your code for exhaustive Loops or Function calls. You can use cProfile or hotshot. More here http://docs.python.org/library/profile.html



回答2:

Python (at least CPython version 2.x) uses reference counting to implement its garbage collector (cf. Why Java and Python garbage collection methods are different?), so it's not really "called", as it is in Java.

Refcounting means that each time a new reference to a given object is created, a counter is incremented, each time the reference is lost (end of scope, reassignment, ...), the counter is decremented. When it reaches 0, the object memory is freed.

So the solution Python offers to your problem is to override the __del__ method of the object:

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

EDIT: According to the link above, there is another mechanism running periodically:

CPython (reference counting is not part of python itself, but part of the C implementation thereof) catches circular references with a separate garbage collection routine that it runs periodically...

but only involved in case of circular references.

EDIT 2: As mentioned in the comments and here, __del__ is not the safest solution. Here is a certainly better way to achieve a similar behavior:

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