Resource management is one of POE's major responsibilities. POE tracks resource ownership and usage, and it knows to release resources when it's done using them. It's also very diligent about reporting leftover resources when it's done running.

The things POE watches are just about everything it deals with: filehandles, timers, events, and even other sessions. It also keeps track of its internal structures, which means that most memory leaks tend to occur in things outside its control.

POE relies heavily on Perl's garbage collection. There are a couple ways to thwart Perl's garbage collection, though, and they tend to thwart POE's as well.

Extra References

POE's design assumes that objects will self destruct when POE release all its references to them. For this to work, however, programs must not keep extra references to objects.

For example, programs should almost never store POE::Session references. The memory consumed by sessions won't be released until those references go away.

The same goes for filehandles. POE will close filehandles when the last select() call or Wheel referring to them is turned off.

Check for:

Extra filehandle references.

Files will not be closed unless all their references are destroyed. Even if they're explicitly closed, their storage space will not be reclaimed until the references are released.

Extra wheel references.

Wheels will not be destroyed until all their references are removed. This compounds the problem of extra filehandle references with the memory overhead of wheels themselves. Furthermore, sessions will not stop on their own if they have wheels, so that's more memory lost.

Extra session references.

Sessions may _stop, but their memory will never be reclaimed if other references to them exist. Their HEAPs will not be destroyed either, and that includes whatever happens to be in them.

Closures.

Closures are wonderful things, but they can be tricky. References passed into code via closures will not be released automatically until the code goes away. This can delay object destruction until after an event handler has executed, confusing POE as to the time (and place) the object died.

If you suspect a closure is holding an object reference too long, explicitly undef the variable holding the reference.

Circular References

Circular references are instances where two or more objects refer to themselves in a circle.

  Object A holds a reference to object B.
  Object B holds a reference to object A.

Each object keeps the other from destructing, resulting in memory that's lost until the program ends. This may be a long time if the program happens to be a daemon.

Check for:

HEAPs holding things they shouldn't.

It's easy to create circular references with object sessions. People often embed session references in objects' $self or store object references in sessions' HEAPs. Generally speaking, neither is necessary:

1. In object sessions, the $_[OBJECT] event handler parameter will include a reference to the object handling the event.

2. POE::Kernel exports $poe_kernel which can be used to determine which session has invoked an object's method.

my $calling_session = $poe_kernel->get_active_session();

3. Once the calling session is known, so is its heap.

my $calling_session_heap = $calling_session->get_heap();

HEAPs holding cross-referenced nested data.

A session's heap may hold references to other things in itself. It's possible to implement circular references when two things in a session's heap refer to themselves. In that case the session will _stop, and it will be DESTROYed. However, the things referring to themselves in the HEAP will linger in memory.

Sessions referring to one another.

Two sessions holding references to each-other in their HEAPs will form a circular reference chain. The sessions may _stop, but they will consume memory until the program ends.

Programs with high session turnover will leak memory until something breaks.

Bad Housekeeping

Often times leaks occur because a developer has built some data structure and never removed things from it. For example, a hash might be used to manage several parallel tasks, but the program may never remove the tasks from the hash when it is done.

It is possible to track the memory use of structures with simple warn() statements.

Scalars:

warn "thing is ", length($heap->{thing}), " bytes";

Hashes:

warn "thing has ", scalar(keys %{$heap->{thing}}), " items";

Lists:

warn "thing is ", length("@{$heap->{thing}}"), " bytes";
warn "thing has ", scalar(@{$heap->{thing}}), " items";

If these numbers increase indefinitely, then you've found your leak. The next step is to check how data goes into the structures and how you're supposed to be removing them.


Please post a message to the mailing list if you've found something not listed here. It may be a bug in POE, or it may be an opportunity to expand this FAQ.