""" Helpers for managing garbage collection. :ivar fileDescriptorResource: A garbage-collection-informing resource tracker for file descriptors. This is used to trigger a garbage collection when it may be possible to reclaim a significant number of file descriptors as a result. Register allocation and release of *bare* file descriptors with this object (file objects, socket objects, etc, have their own integration with the garbage collector and don't need to bother with this). Ported to Python 3. """ __all__ = [ "fileDescriptorResource", ] import gc import attr @attr.s class _ResourceTracker(object): """ Keep track of some kind of resource and trigger a full garbage collection when allocations outnumber releases by some amount. :ivar int _counter: The number of allocations that have happened in excess of releases since the last full collection triggered by this tracker. :ivar int _threshold: The number of excess allocations at which point a full collection will be triggered. """ _counter = attr.ib(default=0) _threshold = attr.ib(default=25) def allocate(self): """ Register the allocation of an instance of this resource. """ self._counter += 1 if self._counter > self._threshold: gc.collect() # Garbage collection of this resource has done what it can do. If # nothing was collected, it doesn't make any sense to trigger # another full collection the very next time the resource is # allocated. Start the counter over again. The next collection # happens when we again exceed the threshold. self._counter = 0 def release(self): """ Register the release of an instance of this resource. """ if self._counter > 0: # If there were any excess allocations at this point, account for # there now being one fewer. It is not helpful to allow the # counter to go below zero (as naturally would if a collection is # triggered and then subsequently resources are released). In # that case, we would be operating as if we had set a higher # threshold and that is not desired. self._counter -= 1 fileDescriptorResource = _ResourceTracker()