[PEAK] memory leaks & stuff
Phillip J. Eby
pje at telecommunity.com
Wed Sep 15 11:50:54 EDT 2004
At 05:06 PM 9/15/04 +0300, alexander smishlajev wrote:
>Yaroslav Samchuk wrote, at 14.09.2004 20:52:
>
>>On the last week we had discovered, that the application, which is
>>developed by our team was leaking memory.
>
>while hunting for this leak, i've got two questions:
>
>- derived conditions Not, Intersect and Union are not exported from
>events.sources. why?
Because they're not intended for direct use: use the ~, &, and | operators
on existing condition objects instead.
>- what's wrong with the following script?
Your Ticker._doEventLoop is an infinite loop, so once you assemble a
Ticker, its Task will run indefinitely, even if you drop all other
references to that Ticker instance. The Task still has a reference to the
Ticker (the 'self' local variable) so it can never be garbage collected.
Therefore, your "leaking" version leaks Ticker instances, one per second.
So, you should be careful to have a way for Tasks to exit, if you intend to
be able to do away with the object(s) they operate on. If you look at e.g.
peak.tools.supervisor, you'll see that child process objects' control Tasks
loop only until the child process exits, so that the process object can be
garbage collected after that. The only Tasks that can safely be infinite
loops in a long-running application are those which will have only a fixed
number of instances, and for which no garbage collection is needed. (For
example, peak.tools.supervisor has a few top-level control tasks that are
infinite loops, but they don't control any resources that need to be
released before the application as a whole exits.)
>=== cut ===
>import gc
>from peak.api import binding, events
>from peak.running import commands, interfaces
>
>class Ticker(binding.Component):
> delay = 1
> evt = binding.Make(events.Condition)
> eventLoop = binding.Obtain(events.IEventLoop)
> def _doEventLoop(self):
> while True:
> yield self.eventLoop.sleep(self.delay)
> events.resume()
> self.evt.set(True)
> _doEventLoop = binding.Make(events.taskFactory(_doEventLoop),
> uponAssembly=True)
>
>class App(commands.AbstractCommand):
>
> mainLoop = binding.Obtain(interfaces.IMainLoop)
>
> def _doEventLoop(self):
> while True:
> yield self.evt; events.resume()
> ### non-leaking:
> #self.evt.set(False)
> ### leaking:
> self._delBinding("evt")
> gc.collect()
> print "Total objects:", len(gc.get_objects())
> _doEventLoop = binding.Make(events.taskFactory(_doEventLoop),
> uponAssembly=True)
>
> evt = binding.Make(lambda self: Ticker(parentComponent=self,
> delay=1).evt)
>
> def _run(self):
> return self.mainLoop.run()
>
>if __name__ == "__main__":
> commands.runMain(App)
>=== cut ===
More information about the PEAK
mailing list