1 | """ |
---|
2 | Helpers for managing garbage collection. |
---|
3 | |
---|
4 | :ivar fileDescriptorResource: A garbage-collection-informing resource tracker |
---|
5 | for file descriptors. This is used to trigger a garbage collection when |
---|
6 | it may be possible to reclaim a significant number of file descriptors as |
---|
7 | a result. Register allocation and release of *bare* file descriptors with |
---|
8 | this object (file objects, socket objects, etc, have their own integration |
---|
9 | with the garbage collector and don't need to bother with this). |
---|
10 | |
---|
11 | Ported to Python 3. |
---|
12 | """ |
---|
13 | |
---|
14 | __all__ = [ |
---|
15 | "fileDescriptorResource", |
---|
16 | ] |
---|
17 | |
---|
18 | import gc |
---|
19 | |
---|
20 | import attr |
---|
21 | |
---|
22 | @attr.s |
---|
23 | class _ResourceTracker(object): |
---|
24 | """ |
---|
25 | Keep track of some kind of resource and trigger a full garbage collection |
---|
26 | when allocations outnumber releases by some amount. |
---|
27 | |
---|
28 | :ivar int _counter: The number of allocations that have happened in excess |
---|
29 | of releases since the last full collection triggered by this tracker. |
---|
30 | |
---|
31 | :ivar int _threshold: The number of excess allocations at which point a |
---|
32 | full collection will be triggered. |
---|
33 | """ |
---|
34 | _counter = attr.ib(default=0) |
---|
35 | _threshold = attr.ib(default=25) |
---|
36 | |
---|
37 | def allocate(self): |
---|
38 | """ |
---|
39 | Register the allocation of an instance of this resource. |
---|
40 | """ |
---|
41 | self._counter += 1 |
---|
42 | if self._counter > self._threshold: |
---|
43 | gc.collect() |
---|
44 | # Garbage collection of this resource has done what it can do. If |
---|
45 | # nothing was collected, it doesn't make any sense to trigger |
---|
46 | # another full collection the very next time the resource is |
---|
47 | # allocated. Start the counter over again. The next collection |
---|
48 | # happens when we again exceed the threshold. |
---|
49 | self._counter = 0 |
---|
50 | |
---|
51 | |
---|
52 | def release(self): |
---|
53 | """ |
---|
54 | Register the release of an instance of this resource. |
---|
55 | """ |
---|
56 | if self._counter > 0: |
---|
57 | # If there were any excess allocations at this point, account for |
---|
58 | # there now being one fewer. It is not helpful to allow the |
---|
59 | # counter to go below zero (as naturally would if a collection is |
---|
60 | # triggered and then subsequently resources are released). In |
---|
61 | # that case, we would be operating as if we had set a higher |
---|
62 | # threshold and that is not desired. |
---|
63 | self._counter -= 1 |
---|
64 | |
---|
65 | fileDescriptorResource = _ResourceTracker() |
---|