List Info

Thread: Re: I'm a newb and need some help




Re: I'm a newb and need some help
user name
2008-02-23 07:37:13
kangax:  

all:
 I should mention that I don't know for sure that this
create-a-
closure-within-a-closure idiom works in terms of the
garbage
collectors out there; I've always intended to go find out
because it
seems like there's a chain involved and it wouldn't
necessarily be
broken by doing that.  I'd be really interested in any
references
folks have to empirical results on that, since as Manu
points out, it
might matter in terms of memory use.  A quick-and-dirty test
in FF2
for Windows suggests that FF doesn't release the context in
this
scenario:

var keeper = null;
function executionContextTest()
{
	var	a;
	var	n;

	a = new Array();
	for (n = 200000; n > 0; --n)
	{
		a[n] = new Date();
	}

//	keeper = function() {
//		alert('This is the keeper function');
//	};

	keeper = (function() {
		return function() {
			alert('This is the keeper function');
		}
	})();
}

(Where I trigger executionContextTest via a button.)  The
commented-
out code would definitely preserve the execution context and
therefore
the array, but the second example is using the
closure-creates-a-
closure idiom.  FF seems to keep all of the execution
contexts alive
(and therefore preserve the array) in this case as well. 
When I run
this, FF's memory use goes up by about 19MB, and doesn't
come down
again until I use another button to release the keeper
reference (and
then an alert to jog the garbage collector).  If I don't
create the
closure at all, the memory is reclaimed as soon as
executionContextTest completes (without having to jog the
garbage
collector).

But again, this was not in any way a scientific test.  If
anyone can
point me at some... 

Manu:  Don't let this bother you in cases where
you're not keeping a
reference to the closure, that's the only time the issue of
keeping
the execution contexts alive comes up.  Use-and-discard
closures are
not a problem (and very useful).
--
T.J. Crowder
tj /crowder software / com

On Feb 23, 12:43 pm, kangax <kan...gmail.com> wrote:
> Wow, that's one thorough explanation.
> Thanks T.J.
>
> On Feb 23, 5:01 am, "T.J. Crowder"
<tjcrow...gmail.com> wrote:
>
> > Hi,
>
> > > Closures is something that (can) cause memory
leaks, right?
>
> > That's a complex topic.   Closures
inherit, and therefore preserve
> > for their lifecycles, all of the local variables
and parameters of the
> > functions they're defined in.  If the closure is
used immediately and
> > discarded, you don't much care.  If you're going
to retain a reference
> > to the closure (for instance, an event handler, or
a dynamically-
> > created instance method), then you want to be
aware of this.  Here's
> > an example of the latter case:
>
> > function myNiftyMethod(param)
> > {
> >     var v1, v2, v3;
>
> >     // ... do something ...
>
> >     // create and retain a closure to do
something
> >     this.thingy = function() {
> >         // ... some code for the closure ...
> >     };
>
> > }
>
> > When myNiftyMethod is executed, it creates a
closure and remembers it
> > on the object instance as this.thingy.  Since the
closure holds a
> > reference to all of myNiftyMethods local variables
and params (even
> > though it doesn't use them), and since the object
instance keeps a
> > reference to the closure, 'param', 'v1', 'v2', and
'v3' all live on
> > for as long as the closure does.  (Modulo cool
JavaScript engine
> > optimisations, which I don't think are common yet
and are harder for
> > the engine to do than it would at first seem.)
>
> > So closures can have memory *implications*; if you
understand how they
> > work, though, and get used to some idioms around
them, you won't cause
> > memory leaks (barring JavaScript engine bugs).
>
> > This is rambling a bit, but here's an example of
the case where you're
> > using the closure immediately and discarding it:
>
> > function myNiftyMethod(someArray)
> > {
> >     var v1, v2, v3;
>
> >     // ... do something ...
>
> >     // create and retain a closure to do
something
> >     someArray.each(function(item) {
> >         item.doSomethingCool();
> >     });
>
> > }
>
> > You don't keep a reference to the closure used in
the each() method,
> > so you don't have to consider the implications of
myNiftyMethod's
> > parameters and variables being retained.  And it's
a very powerful and
> > expressive way to deal with each item in the
array.
>
> > > - I'm getting lost in how you constructed the
onSuccess callback...
>
> > That's easy to do.   He's
using a closure to construct and return
> > another closure; it's the inner one that gets
assigned to the
> > onSuccess handler and retained, the outer one is
run immediately and
> > discarded.  If you look carefully at the code
defining the onSuccess
> > handler, you'll see that the entire outer closure
is wrapped in parens
> > -- the opening paren is right after
"onSuccess:", and then right at
> > the end of the closure you see the closing paren
followed by "(item)"
> > -- that "(item)" tells you he's
*executing* the outer closure right
> > then, not just creating it.  When it runs, the
outer closure creates
> > the inner closure and returns it.  *That's* what
gets assigned to
> > onSuccess, the reference to the inner closure. 
The outer closure has
> > only the param it needs (item) and no local
variables, so the inner
> > closure only preserves the information it really
needs, not all of the
> > local variables where all of this is running.
>
> > Hope this helps,
> > --
> > T.J. Crowder
> > tj /crowder software / com
>
> > On Feb 23, 7:34 am, "Manu
Temmerman-Uyttenbroeck"
>
> > <manu.temmermanuyttenbro...gmail.com> wrote:
> > > Hi,
>
> > > Closures is something that (can) cause memory
leaks, right?
> > > kangax, would you mind explaining in a bit
more detail why you wrote the
> > > code like you wrote it? I'm a bit lost in it.
I restructured the code you
> > > wrote a bit...http://pastie.caboo.se/
156248
> > > - Is there a reason why you don't write a ';'
after the new Ajax.Request
> > > (...)?
> > > - Is there a reason why you don't write a ';'
after the
> > > someArray.each(function(item)
> > > { ... })?
> > > - I'm getting lost in how you constructed the
onSuccess callback...
>
> > > Thx...
>
> > > Manu.
>
> > > On Fri, Feb 22, 2008 at 11:11 PM, kangax
<kan...gmail.com> wrote:
>
> > > > Looks like a closure issue to me (solved
with another closure).
> > > > Also, is that an array you are iterating
over using "for..in" ?
>
> > > > siteListArray.each(function(item) {
> > > >  var url =
'functions.php?command=numberOfErrors&site=' + item;
> > > >  new Ajax.Request(url, {
> > > >    onSuccess: (function(item) { return
function(t) {
> > > >      $('sidebar_site_div_' +
item).update(t.responseText);
> > > >    }})(item)
> > > >  })
> > > > })
>
> > > > - kangax
>
> > > > On Feb 22, 4:02 pm, Chach
<carterharri...mac.com> wrote:
> > > > > Hi everybody,
>
> > > > > I'm just getting kicked off on
prototype and I'm having a problem that
> > > > > I'm hoping to get some help on.. 
I've had good success with
> > > > > Ajax.Updater, but now I'm trying to
use Ajax.Request with the use of
> > > > > its callback abilities.  My issue
is that I'm trying to get a hold of
> > > > > one of the Element objects in the
DOM using $('element'), however the
> > > > > name of the element can vary and so
I have to assemble the name using
> > > > > the value in an array.  It's almost
like the siteListArray[x] does not
> > > > > work in the callback.  Is it
possible that the callback cannot see a
> > > > > variable that was declared earlier
in my code at a global scope?
> > > > > Thanks in advance.
>
> > > > > for (x in siteListArray)
> > > > > {
> > > > >         var url =
'functions.php?command=numberOfErrors&site=' +
> > > > > siteListArray[x];
> > > > >         new Ajax.Request(url, {
> > > > >                 asynchronous:true,
> > > > >                 onComplete:
function(transport) {
> > > > >                        
$('sidebar_site_div_' +
> > > > >
siteListArray[x]).update(transport.responseText);
> > > > >                 }
> > > > >         });
>
> > > > > }
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the
Google Groups "Ruby on Rails: Spinoffs" group.
To post to this group, send email to
rubyonrails-spinoffsgooglegroups.com
To unsubscribe from this group, send email to
rubyonrails-spinoffs-unsubscribegooglegroups.com
For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=
en
-~----------~----~----~----~------~----~------~--~---


[1]

about | contact  Other archives ( Real Estate discussion Medical topics )