How to free memory in the Perl [closed]

2019-06-09 16:55发布

问题:

I have daemon with children on perl. For daemonize i use Proc::Daemon. Control daemon and children connected to DB(DBI lib), childs collect mail via imap (Mail::IMAPClient lib) too. I undef all variables in code of children, but over time, a child who works more than anyone, consume a lot of memory. ps output:

user   16521  0.6  1.6 135560 16516 ?        S    10:47   0:54 perl remote_imap.pl
user   16523  0.2 20.0 331976 201764 ?       S    10:47   0:21 perl remote_imapd.pl 16521
user   16525  0.1  3.0 157792 30720 ?        S    10:47   0:09 perl remote_imapd.pl 16521
user   16527  0.1  3.0 157796 30704 ?        S    10:47   0:08 perl remote_imapd.pl 16521
user   16529  0.1  3.0 157796 30572 ?        S    10:47   0:09 perl remote_imapd.pl 16521
user   16531  0.1  3.0 157792 30612 ?        S    10:47   0:08 perl remote_imapd.pl 16521

for sleep i use usleep from Time::HiRes lib. In remote_imap.pl usleep(100000), In remote_imapd.pl - usleep(500000).

Why memory is not released, because I did andef for all variables (except id_connet to DB)? If you want, I'll add code.

Main daemon remote_imap.pl Child remote_imapd.pl

回答1:

Perl uses reference counting to manage it's memory space. When you declare a variable, a small amount is set aside. When you use it, more memory is occupied. Perl may reuse the memory space once a variable is no longer referenced at all.

That's why it's quite important to keep lexical scopes small, and avoid global variables - something global is 'in scope' throughout your code, even if it's only used once.

The gotcha is circular references. A circular reference never becomes unreferenced, so perl can't 'release' it automatically. That's also fairly easy to end up with inside objects - if part of an object has a reference to another part of the object.

That's why you have things like weaken().

I'll note in the examples you give above - the child process (why did you call the files the same thing?) you've lexically scoped:

my (@array, @is_ok, @params, $user_id, $user_remote_id, $is_delete, $error_count, $is_first, $server, $port, $login, $password, $is_ssl, $no_error, $error_text, $pid, $date, $date_up, $exists, $q, $sth, $rv);

Outside your while loop, and tried to 'tidy up' by:

(@array, @is_ok, @params, $user_id, $user_remote_id, $is_delete, $error_count, $is_first, $server, $port, $login, $password, $is_ssl, $no_error, $error_text, $pid, $date, $date_up, $exists, $q, $sth, $rv) = undef;

Out of interest - why are you doing this? Could you not scope them within your while loop, and then you won't need to reuse them? I don't know that's necessarily your problem though - it could quite easily be in one of the libraries you import. The fact that it's happening with the busier child implies that each loop something is getting to an array or object that's persisting.