hi:
I try to write windows service with win32::daemon. but I found the service will leak memory after running for long time.
it is caused by the callback event. the more callback is called, the more memory leaked.
I tried active perl and strawberry perl 5.18/5.22 64bit/32bit under winxp,win7,2008R2 but the situation is the same. 64bit is better but it still happen. I strip the code below to a "memory-leak" service. and tune the callback frequency to 30 ms to speed up the leak. so you can see leak after minutes/hours. hope someone can find out why this happened.
#!/usr/bin/perl
use strict;
use warnings;
use Win32::Daemon;
use Getopt::Long;
my @cmd = @ARGV;
my ($opt_g,$opt_h,$opt_i,$opt_r);
if (! GetOptions('g=s' =>\$opt_g, 'h' => \$opt_h, 'i' => \$opt_i, 'r'
+=>\$opt_r)){
print "command line wrong !!!\n";
exit(1);
}
if ($opt_h or ! @cmd){
print <<EOF;
Usage: memory-leak [options]
test perl service memory-leak
-i install memory-leak Service
-r remove memory-leak Service
-h help message
-g (internal use only)
EOF
exit(0);
}
# get program name
our $fn = Win32::GetFullPathName($0);
our ($cwd,$bn,$ext) = ($fn =~ /^(.*\\)(.*)\.(.*)$/ )[0..2];
if ($opt_i){
# install service
# Determine service's path to executable based on file extension
my ($path,$parameters);
if ($ext eq "pl"){
# Source perl script - invoke perl interpreter
$path = "\"$^X\"";
# The command includes the -g go switch needed to enter servic
+e mode
$parameters = "\"$fn\" -g go";
}elsif ($ext eq "exe"){
# Compiled perl script - invoke the compiled script
$path = "\"$fn\"";
$parameters = "-g go";
}else{
# Invalid file type?
print "Can not install service for $fn,file extension $ext not
+ supported\n";
exit(1);
}
# Populate the service configuration hash
my %srv_config = (
name => "memory-leak",
display => "memory-leak",
path => $path,
description => "memory-leak",
parameters => $parameters,
service_type => SERVICE_WIN32_OWN_PROCESS,
start_type => SERVICE_AUTO_START
);
# Install the service
if (Win32::Daemon::CreateService(\%srv_config)){
print "memory-leak Service installed successfully\n";
}else{
print "Failed to install service: $!\n";
exit(1);
}
}elsif ($opt_r){
# remove service
if (Win32::Daemon::DeleteService("memory-leak")){
print "memory-leak Service uninstalled successfully\n";
}else{
print "Failed to uninstall service: $!\n";
exit(1);
}
}elsif ($opt_g eq "go"){
Win32::Daemon::AcceptedControls(SERVICE_ACCEPT_STOP | SERVICE_ACCE
+PT_SHUTDOWN);
sleep(1);
Win32::Daemon::RegisterCallbacks({
start => \&callback_start,
timer => \&callback_running,
stop => \&callback_stop,
}) or die("register callback faild");
my $freq = 30;
my %context = (
last_state => SERVICE_STOPPED,
start_time => time(),
);
Win32::Daemon::StartService(\%context,$freq);
}else{
print "No valid options passed - nothing done\n";
}
exit(0);
sub callback_start{
my ($event,$context) = @_;
$context->{last_state} = SERVICE_RUNNING;
Win32::Daemon::State(SERVICE_RUNNING);
return(SERVICE_RUNNING);
}
sub callback_running{
my ($event,$context) = @_;
if ( SERVICE_CONTROL_TIMER == Win32::Daemon::State()){
}
}
sub callback_stop{
Win32::Daemon::State(SERVICE_STOPPED);
sleep(2);
Win32::Daemon::StopService();
return(SERVICE_STOPPED);
}