Search code examples
pythonpython-2.7garbage-collectionatexit

Cannot unregister functions from atexit in python 2.7


First, I wrote a recording class with a flush method:

class Recorder
    def __init__(self, buffer_size, path):
        self._big_buffer = np.array(*buffer_size)
        self._path = path
    def push(self, data):
        # insert in self._big_buffer
        # if self._big_buffer is full:
        #     self._flush()
    def flush(self):
        # write buffer to disk (self._path)

Then, I wanted to flush at exit: when manually stopped, crashed or whatever reason.

So I used:

def __init__(self):
    (...)
    atexit.register(self.flush)

And it worked pretty well.

But now, I want to record, stop recording, record again, multiple times, with a different buffer size and to a different path. So I have to discard, then instanciate several Recorder. It kind of works, but older Recorder's memory (containing some fat self._big_buffer̀) is not freed since it's retained by atexit. Even when I explicitly call del. I can't atexit.unregister(self._flush) since it's Python 3 only.

I would prefer not to reuse existing instances, but discarding older instances and create new ones.

How would you handle such a case?


Solution

  • You can try using a weak reference to the atexit handler, so the object won't be retained if it is deleted elsewhere:

    import atexit
    import weakref
    
    class CallableMethodWeakRef:
        def __init__(self, object, method_name):
            self.object_ref = weakref.ref(object)
            self.method_name = method_name
        def __call__(self):
            object = self.object_ref()
            if object:
                getattr(object, self.method_name)()
    
    class Recorder:
        def __init__(self, *args):
            atexit.register(CallableMethodWeakRef(self, 'flush'))
    
        def flush(self):
            print 'flushing'
    

    The method is passed as a string in order to avoid a lot of problems with bound method weak references, if you find it disturbing you can always use a BoundMethodWeakref implementation like this one: http://code.activestate.com/recipes/578298-bound-method-weakref/