PerlOnTheWay has asked for the wisdom of the Perl Monks concerning the following question:
sub once { my $wrapper; $wrapper = sub { print 1; }; weaken $wrapper; return $wrapper; } my $on = once; $on->();
I don't see any difference with or without weaken $wrapper;,what's it there for?
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: What's the weaken here for?
by ww (Archbishop) on Jan 20, 2012 at 02:27 UTC | |
Scalar::Util
You'll also find a discussion in the section on references in "Learning Perl" (O'Reilly). | [reply] |
|
Re: What's the weaken here for?
by tobyink (Canon) on Jan 20, 2012 at 08:39 UTC | |
Unlike some other languages, Perl performs automatic garbage collection. Say you've defined a variable my $str = 'Hello world' then that needs to be stored in memory somewhere. When the variable goes out of scope, and Perl knows that it's not going to be used again, Perl's garbage collector can free the area of memory it was being stored in (so that the memory can be used for storing something else). In some cases you end up with circular references:
OK, that's a contrived example, but circular references do come up in real code all the time:
Now perhaps the $wife object contains a reference to $husband and vice versa. In cases like this, Perl's garbage collector perhaps considers freeing the memory used by $wife but sees that $wife is still being referred to by $husband, so it can't free that memory until $husband is destroyed. But when it considers freeing the memory used by $husband it sees that $husband is being referred to be $wife, so it can't free anything there either. Technically the way Perl does this is by maintaining a "reference count" for each thing that's in memory - in other words, a count of how many variables and references are pointing at it. This catch-22 situation prevents either of the objects being freed from memory until the program exits. In short-running programs, this is often not a problem. But for long-running processes, it results in a memory leak - the program's memory consumption grows and grows over time. weaken (found in the Scalar::Util package, which has been bundled with Perl seince 5.7.3) breaks the catch-22. It allows you to mark a reference as "weak" in which case it won't count towards the reference count. As somebody else pointed out, in the original code (but not your cut-down example), $wrapper forms a closure over itself, which is a type of circular reference. This will result in memory leaking each time once is called. (Though judging by the function name, it is presumably only called once?) Thus weaken is used to break the circularity (as far as the garbage collector is concerned), and prevent a memory leak. | [reply] [d/l] [select] |
|
Re: What's the weaken here for?
by Anonymous Monk on Jan 20, 2012 at 02:29 UTC | |
I don't see any difference with or without weaken $wrapper;,what's it there for? Where exactly? How are you checking to see a difference?
As you notice, REFCNT doesn't change :) Yeah, that is not a use case for weaken, you use weaken when you have circular references, say
| [reply] [d/l] [select] |
by PerlOnTheWay (Monk) on Jan 20, 2012 at 03:11 UTC | |
The actual code is the sub once of Mojo::EventEmitter https://github.com/kraih/mojo/blob/master/lib/Mojo/EventEmitter.pm The author must have done this for some reason... | [reply] [d/l] [select] |
by BrowserUk (Patriarch) on Jan 20, 2012 at 03:16 UTC | |
The author must have done this for some reason... Because in the real code, unlike your simplification of it, the weakened sub reference forms a closure over itself:
Ie. It contains a circular reference which would leak memory without the weakening. For example, with the weaken commented, this leaks like a sieve:
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] [select] |
by Anonymous Monk on Jan 20, 2012 at 03:38 UTC | |
The actual code is the sub once of Mojo::EventEmitter The author must have done this for some reason... Yeah, well Mr. Sherlock, that code is different than what you posted. The reason is always the same, circular references prevent release of memory
The actual code, which you should have copy/pasted to get a reasonable answer, since editing code you don't understand changes its meaning
How do I post a question effectively? says, when reducing code size, reduce to the essence, don't change the essence :) | [reply] [d/l] [select] |
by PerlOnTheWay (Monk) on Jan 20, 2012 at 05:44 UTC | |
by Anonymous Monk on Jan 20, 2012 at 07:55 UTC | |