I noticed that when using Tk with POE. I had about a 12-8k/sec memory
leak. I managed to track it down to the
$poe_main_window->afterIdle(....) calls in theloop code for Tk. As far
as I can tell it's just with that one call. Here is a patch that works
around the leak. I realize the 'afterIdle' calls are used for a reason
but I find the persistant leak worse. I posted a report to the ptk list.
It's beyond my present time vs. ability constraints to track down and
fix. Hopefully they fix it soon.
Jason Adams
diff -Naur POE-0.29.orig/lib/POE/Loop/TkActiveState.pm
POE-0.29/lib/POE/Loop/TkActiveState.pm
--- POE-0.29.orig/lib/POE/Loop/TkActiveState.pm 2003-12-12 04:05:06.000000000 +0000
+++ POE-0.29/lib/POE/Loop/TkActiveState.pm 2004-08-25 18:04:55.000000000 +0000
@@ -114,6 +114,8 @@
#
# -><- We should really stop the poller when there are no handles to
# watch and resume it as needed.
+{
+ my $firstTimeFlag=1;
sub _poll_for_io {
if (defined $_handle_poller) {
@@ -243,15 +245,21 @@
# Dispatch whatever events are due.
$poe_kernel->_data_ev_dispatch_due();
- # Reset the poller.
- $_handle_poller = $poe_main_window->afterIdle(
- [ sub {
- $_handle_poller->cancel();
- undef $_handle_poller;
- $_handle_poller = $poe_main_window->after(100, [\&_poll_for_io]);
- }
- ]
- );
+ if($firstTimeFlag) {
+ # Reset the poller.
+ $_handle_poller = $poe_main_window->afterIdle(\&_setPollOnIdle);
+ $firstTimeFlag=0;
+ } else {
+ _setPollOnIdle()
+ }
+}
+
+sub _setPollOnIdle {
+ $_handle_poller->cancel() if($_handle_poller);
+ undef $_handle_poller;
+ $_handle_poller = $poe_main_window->after(100, [\&_poll_for_io]);
+}
+
}
1;
diff -Naur POE-0.29.orig/lib/POE/Loop/TkCommon.pm POE-0.29/lib/POE/Loop/TkCommon.pm
--- POE-0.29.orig/lib/POE/Loop/TkCommon.pm 2004-01-21 17:27:01.000000000 +0000
+++ POE-0.29/lib/POE/Loop/TkCommon.pm 2004-08-25 18:04:55.000000000 +0000
@@ -76,6 +76,8 @@
# Tk timer callback to dispatch events.
my $last_time = time();
+{
+ my($firstTimeFlag)=1;
sub _loop_event_callback {
if (TRACE_STATISTICS) {
@@ -106,25 +108,12 @@
# Replace it with an idle event that will reset the alarm.
- $_watcher_timer = $poe_main_window->afterIdle(
- [
- sub {
- $_watcher_timer->cancel();
- undef $_watcher_timer;
-
- my $next_time = $poe_kernel->get_next_event_time();
- if (defined $next_time) {
- $next_time -= time();
- $next_time = 0 if $next_time < 0;
-
- $_watcher_timer = $poe_main_window->after(
- $next_time * 1000,
- [\&_loop_event_callback]
- );
- }
- }
- ],
- );
+ if($firstTimeFlag) {
+ $_watcher_timer = $poe_main_window->afterIdle( \&_loop_wait_for_event);
+ $firstTimeFlag=0;
+ } else {
+ _loop_wait_for_event();
+ }
# POE::Kernel's signal polling loop always keeps one event in the
# queue. We test for an idle kernel if the queue holds only one
@@ -145,6 +134,23 @@
# And back to Tk, so we're in idle mode.
$last_time = time() if TRACE_STATISTICS;
}
+}
+
+sub _loop_wait_for_event{
+ $_watcher_timer->cancel() if($_watcher_timer);
+ undef $_watcher_timer;
+
+ my $next_time = $poe_kernel->get_next_event_time();
+ if (defined $next_time) {
+ $next_time -= time();
+ $next_time = 0 if $next_time < 0;
+
+ $_watcher_timer = $poe_main_window->after(
+ $next_time * 1000,
+ [\&_loop_event_callback]
+ );
+ }
+}
#------------------------------------------------------------------------------
# Tk traps errors in an effort to survive them. However, since POE