Front page | perl.perl5.porters |
Postings from June 2009
Re: DESTROY: is there any predictability about when it's called?
Thread Previous
|
Thread Next
From:
demerphq
Date:
June 14, 2009 03:00
Subject:
Re: DESTROY: is there any predictability about when it's called?
Message ID:
9b18b3110906140259x6e2901e8y330026d340b079bc@mail.gmail.com
2009/6/13 Andy Armstrong <andy@hexten.net>:
> I'm writing some code that catches memory leaks:
>
> leakguard {
> # do something that leaks
> };
>
> If there are any object leaks inside the block it should warn at exit. The
> leakguard sub looks like this:
>
> sub leakguard(&@) {
> my $block = shift;
> my $state = My::Mem::State->new( @_ );
> my $rc = $block->();
> my ( undef ) = ( $state );
> return $rc;
> }
>
> My::Mem::State checks for leaked blessed objects when its DESTROY method is
> called. The problem is that it gets false positives from objects allocated
> inside $block for which DESTROY is pending but get DESTROYed /after/ the
> My::Mem::State.
>
> On 5.10 the my ( undef ) = ( $state ) seems to work to force $state to be
> destroyed late enough to avoid false positives - but that's a bit heuristic
> for my tastes. Is there a reliable way to flush pending DESTROYs or some
> other way to guarantee that $state is lives longer than anything allocated
> by $block?
I dont really understand this code. The correct way to tell perl to
free memory in a block is to explicitly undef the variable.
Also, you have to be careful with the term "leak" in perl.
You see, perl trades memory for speed pretty much always. So for
instance check this:
demerphq@gemini:~$ perl -MDevel::Peek -e'for (reverse 1..10) { my $x;
warn "len: ", defined $x ? length($x): "undef","\n"; Dump($x); $x="x"
x $_; }'
len: undef
SV = NULL(0x0) at 0x8153cdc
REFCNT = 1
FLAGS = (PADBUSY,PADMY)
len: undef
SV = PV(0x8154ae8) at 0x8153cdc
REFCNT = 1
FLAGS = (PADBUSY,PADMY)
PV = 0x8176b78 "xxxxxxxxxx"\0
CUR = 10
LEN = 12
len: undef
SV = PV(0x8154ae8) at 0x8153cdc
REFCNT = 1
FLAGS = (PADBUSY,PADMY)
PV = 0x8176b78 "xxxxxxxxx"\0
CUR = 9
LEN = 12
len: undef
SV = PV(0x8154ae8) at 0x8153cdc
REFCNT = 1
FLAGS = (PADBUSY,PADMY)
PV = 0x8176b78 "xxxxxxxx"\0
CUR = 8
LEN = 12
len: undef
SV = PV(0x8154ae8) at 0x8153cdc
REFCNT = 1
FLAGS = (PADBUSY,PADMY)
PV = 0x8176b78 "xxxxxxx"\0
CUR = 7
LEN = 12
len: undef
SV = PV(0x8154ae8) at 0x8153cdc
REFCNT = 1
FLAGS = (PADBUSY,PADMY)
PV = 0x8176b78 "xxxxxx"\0
CUR = 6
LEN = 12
len: undef
SV = PV(0x8154ae8) at 0x8153cdc
REFCNT = 1
FLAGS = (PADBUSY,PADMY)
PV = 0x8176b78 "xxxxx"\0
CUR = 5
LEN = 12
len: undef
SV = PV(0x8154ae8) at 0x8153cdc
REFCNT = 1
FLAGS = (PADBUSY,PADMY)
PV = 0x8176b78 "xxxx"\0
CUR = 4
LEN = 12
len: undef
SV = PV(0x8154ae8) at 0x8153cdc
REFCNT = 1
FLAGS = (PADBUSY,PADMY)
PV = 0x8176b78 "xxx"\0
CUR = 3
LEN = 12
len: undef
SV = PV(0x8154ae8) at 0x8153cdc
REFCNT = 1
FLAGS = (PADBUSY,PADMY)
PV = 0x8176b78 "xx"\0
CUR = 2
LEN = 12
demerphq@gemini:~$ perl -MDevel::Peek -e'for (1..10) { my $x; warn
"len: ", defined $x ? length($x): "undef","\n"; Dump($x); $x="x" x $_;
}'
len: undef
SV = NULL(0x0) at 0x81546c0
REFCNT = 1
FLAGS = (PADBUSY,PADMY)
len: undef
SV = PV(0x8154ae8) at 0x81546c0
REFCNT = 1
FLAGS = (PADBUSY,PADMY)
PV = 0x8177c30 "x"\0
CUR = 1
LEN = 4
len: undef
SV = PV(0x8154ae8) at 0x81546c0
REFCNT = 1
FLAGS = (PADBUSY,PADMY)
PV = 0x8177c30 "xx"\0
CUR = 2
LEN = 4
len: undef
SV = PV(0x8154ae8) at 0x81546c0
REFCNT = 1
FLAGS = (PADBUSY,PADMY)
PV = 0x8177c30 "xxx"\0
CUR = 3
LEN = 4
len: undef
SV = PV(0x8154ae8) at 0x81546c0
REFCNT = 1
FLAGS = (PADBUSY,PADMY)
PV = 0x8177c30 "xxxx"\0
CUR = 4
LEN = 8
len: undef
SV = PV(0x8154ae8) at 0x81546c0
REFCNT = 1
FLAGS = (PADBUSY,PADMY)
PV = 0x8177c30 "xxxxx"\0
CUR = 5
LEN = 8
len: undef
SV = PV(0x8154ae8) at 0x81546c0
REFCNT = 1
FLAGS = (PADBUSY,PADMY)
PV = 0x8177c30 "xxxxxx"\0
CUR = 6
LEN = 8
len: undef
SV = PV(0x8154ae8) at 0x81546c0
REFCNT = 1
FLAGS = (PADBUSY,PADMY)
PV = 0x8177c30 "xxxxxxx"\0
CUR = 7
LEN = 8
len: undef
SV = PV(0x8154ae8) at 0x81546c0
REFCNT = 1
FLAGS = (PADBUSY,PADMY)
PV = 0x8177c30 "xxxxxxxx"\0
CUR = 8
LEN = 12
len: undef
SV = PV(0x8154ae8) at 0x81546c0
REFCNT = 1
FLAGS = (PADBUSY,PADMY)
PV = 0x8177c30 "xxxxxxxxx"\0
CUR = 9
LEN = 12
Notice that the memory in the first one "grows" with each iteration,
and is not freed at the end of the loop. The reverse makes this much
clearer and explains why. See, perl doesnt bother freeing the pv, it
just modifies it. This avoids calling realloc/malloc all the time, and
is a desirable optimisation. It also means that this code would appear
to "leak", except its not leaking as leaking implies losing memory
unintentionally, and this is a most deliberate optimisation.
However this also often bites people who are only thinking about
memory profile and not speed as well. So for instance if that var
ended up being several MB then those MB would appear to "leak".
So be careful with using base memory footprint as a measure of
"leaked" memory. Its not a leak, its a deliberate optimisation. To me
there are two forms of leaked memory in perl. C level, which you need
to use C level tools sets to find, (like valgrind), and refcycle
leaks, which are a Hard Problem and probably have to be attacked
either with a debug mode perl or with code analysis.
Forgive me if you knew this. And i guess you did say "leaked blessed
objects" but i dont know what you mean by that except for reference
cycles, and well in that case DESTROY gets called at perl destruction,
and isnt going to be relevent to your question.... (er, i think).
Maybe i should have drunk more coffee before wrtiting this....
mea-culpa in advance.
Yves
--
perl -Mre=debug -e "/just|another|perl|hacker/"
Thread Previous
|
Thread Next