From: David Mark on
On Jul 22, 6:52 pm, "Richard Cornford" <Rich...(a)litotes.demon.co.uk>
wrote:
> David Mark wrote:
> > On Jul 22, 1:34 pm, Richard Cornford wrote:
> >>> On Jul 22, 9:50 am, David Mark wrote:
> <snip>
> >>>> That's right, you will have to slog through jQuery's code
> >>>> again to determine whether it is minding its business with
> >>>> regard to avoiding circular references. What your code does
> >>>> is actually immaterial. Confusing and time-consuming isn't it?
> <snip>
> >> Outside of JQuery you can do whatever you like to avoid the
> >> memory leak-inducing circular chains of references, but JQuery
> >> creates them for you when you use its - bind - method. Now the
> >> question is whether JQuery cleans these circular chains of
> >> reference up on its own, or whether you are going to have to
> >> take some remedial action to remove bound methods; time to "slog
> >> through jQuery's code again". And if it turns out that you have
> >> to take action yourself then maybe you don't have to avoid
> >> creating circular chins of reference as you would have
> >> the opportunity to break any you did create at the same
> >> time as you set about breaking JQuery's.
>
> > IIRC, they use an unload listener to offset their own previous
> > mistakes as used to be preached by Douglas Crockford (and
> > hopefully he's since renounced the strategy).  Of course, they'd
> > have been much better off avoiding (or fixing) the mistakes.  :)
>
> If you want someone to experience the 'joys' of searching through the
> sauce code of a highly interdependent javascript library in order to
> find a definitive answer to a specific question then it does not seem
> like a good idea to tell then the answer before hand.

Fair enough.

>
> Unload handlers address some of the issues but they leave the question
> of what happens in the meanwhile. If an unbroken circular chain of
> references is going to prevent garbage collection until the browser is
> shut down, effected DOM elements that are removed/freed/replaced are not
> going to be garbage collected themselves in the meanwhile. This would
> become an issue in the 'single page' style of web application, where you
> are expected to use the application for some time before unloading it.
> Quite a few DOM Elements, some with event handlers, are likely to be
> cycled through the DOM, and normally once they are finished with the
> desire would be to have the objects garbage collected (especially as IE
> 6's performance drops off as its memory consumption increases). An
> unload handler based approach is not sufficiently proactive as to
> achieve that.

Right. Hence the myriad mystical incantations out there (e.g. trying
to force IE to collect garbage using a method that has been
demonstrated to be useless).

>
> > The idea that such listeners are unneeded (and can be very
> > destructive) has only just started to reach the general public
> > (years late as usual).  As usual, jQuery's authors are at the
> > rear of the pack.  They'll get it eventually (maybe even after
> > reading this thread).
>
> The memory leak issues are reducing with the passage of time. Even IE 6
> appears to have had updates that reduce the scope of the problem. We may
> not be that far away from the end of whole circular reference issue, and
> so be able to stop worrying about this entirely.
>

Suits me. And isn't that always the way that the various libraries
"solve" problems? In other words, waiting for them to expire and then
removing their stacked up (and botched) attempts at solutions. No
wonder they want to "ban" IE6. :)
From: John G Harris on
On Thu, 22 Jul 2010 at 11:53:52, in comp.lang.javascript, David Mark
wrote:

<snip>
>> Either way, the object is a member of the class of all possible such
>> objects.
>
>But you are playing loose with those terms. Technically speaking,
>there are no classes in JS.
<snip>

I'm using 'class' in the same way as Bertrand Russell (he of Principia
Mathematica), and a lot of modern maths textbooks, and a lot of
philosophy textbooks. Just because some OO authors picked up the term
and ran away with it, often spouting nonsense, doesn't stop us using the
normal meaning. Especially in a language that has no class definitions.

John
--
John Harris
From: David Mark on
On Jul 23, 3:34 pm, John G Harris <j...(a)nospam.demon.co.uk> wrote:
> On Thu, 22 Jul 2010 at 11:53:52, in comp.lang.javascript, David Mark
> wrote:
>
>   <snip>>> Either way, the object is a member of the class of all possible such
> >> objects.
>
> >But you are playing loose with those terms.  Technically speaking,
> >there are no classes in JS.
>
>   <snip>
>
> I'm using 'class' in the same way as Bertrand Russell (he of Principia
> Mathematica), and a lot of modern maths textbooks, and a lot of
> philosophy textbooks. Just because some OO authors picked up the term
> and ran away with it, often spouting nonsense, doesn't stop us using the
> normal meaning. Especially in a language that has no class definitions.

You don't think using "class" to debscribe objects created in a class-
free language will lead to confusion?
From: Garrett Smith on
On 2010-07-22 10:34 AM, Richard Cornford wrote:
> On Jul 22, 2:48 pm, Josh Russo wrote:
>> On Jul 22, 9:50 am, David Mark wrote:
>>> On Jul 22, 5:08 am, Josh Russo wrote:
> <snip>
[...]

>
> | if ( !eventHandle ) {
> | elemData.handle = eventHandle = function() {
> | // Handle the second event of a trigger and when
> | // an event is called after a page has unloaded
> | return typeof jQuery !== "undefined"&&
> | !jQuery.event.triggered ?
> | jQuery.event.handle.apply( eventHandle.elem, arguments ):
> | undefined;
> | };
> | }
> |
> | // Add elem as a property of the handle function
> | // This is to prevent a memory leak with non-native
> | // events in IE.
> | eventHandle.elem = elem;
> ^^^^^^^^^^^^^^^^^^^^^^^
> Here the function either retrieved or created above and assigned to
> the variable - eventHandle - has a property added to it with the name
> 'elem' and a reference to a object that is likely to be a DOM Element
> assigned to it.
>
> JQuery comments never seem to explain the more unexpected aspects of
> what JQuery code does. IE has memory leak problems (or at lest older
> versions of it do), but what does "non-native events" mean, and how is
> this going to prevent the memory leaks?
>

The `elem` property could be used in `call` to resolve context to `elem`
and could deleted later in the "remove" method.

| function getBoundCallback(o, cb) {
| // no binding for window, because:
| // 1) context is already global and
| // 2) removing onunload handlers is skipped (see cleanUp);
| if (o === window)
| return cb;
| function bound(ev) {
| bound.original.call(bound.context, ev || window.event);
| }
| bound.original = cb;
| bound.context = o;
| cb = o = null;
| return bound;
| }

And in the `remove` method, I call removeFromCallstack which deletes the
properties `context` `original` from the `bound` method.

| function removeFromCallStack(callStack, callback) {
| var cb, i, len;
| for (i = 0, len = callStack.length; i < len; i++) {
| cb = callStack[i];
| if ((cb.original || cb) === callback) {
| delete cb.original;
| delete cb.context;
| return callStack.splice(i, 1)[0];
| }
| }
| return null;
| }

> Possibly the idea is that if the variable - elem - where referenced in
> the - jQuery.event.handle.apply( ... - line above, and not nulled at
> the end of this method, then there would be an obvious circular chain
> of reference, which there would be. But what follows rather negates
> any effort taken to avoid that circle.
>

Right, they null it, and then save the reference to `elem` as a property
to the function, creating a circular reference.

The chain can be broken by deleting the `elem` property in the remove
method.

[...]

>
> Outside of JQuery you can do whatever you like to avoid the memory
> leak-inducing circular chains of references, but JQuery creates them
> for you when you use its - bind - method. Now the question is whether
> JQuery cleans these circular chains of reference up on its own, or
> whether you are going to have to take some remedial action to remove
> bound methods; time to "slog through jQuery's code again".

I see near the bottom of `remove`:
| if ( jQuery.isEmptyObject( events ) ) {
| var handle = elemData.handle;
| if ( handle ) {
| handle.elem = null;
| }
--
Garrett
From: David Mark on
On Jul 25, 10:29 pm, Garrett Smith <dhtmlkitc...(a)gmail.com> wrote:
> On 2010-07-22 10:34 AM, Richard Cornford wrote:> On Jul 22, 2:48 pm, Josh Russo wrote:
> >> On Jul 22, 9:50 am, David Mark wrote:
> >>> On Jul 22, 5:08 am, Josh Russo wrote:
> > <snip>
>
> [...]
>
>
>
>
>
>
>
> > |     if ( !eventHandle ) {
> > |       elemData.handle = eventHandle = function() {
> > |         // Handle the second event of a trigger and when
> > |         // an event is called after a page has unloaded
> > |         return typeof jQuery !== "undefined"&&
> > |                              !jQuery.event.triggered ?
> > |           jQuery.event.handle.apply( eventHandle.elem, arguments ):
> > |           undefined;
> > |       };
> > |     }
> > |
> > |     // Add elem as a property of the handle function
> > |     // This is to prevent a memory leak with non-native
> > |     // events in IE.
> > |     eventHandle.elem = elem;
> >        ^^^^^^^^^^^^^^^^^^^^^^^
> > Here the function either retrieved or created above and assigned to
> > the variable - eventHandle - has a property added to it with the name
> > 'elem' and a reference to a object that is likely to be a DOM Element
> > assigned to it.
>
> > JQuery comments never seem to explain the more unexpected aspects of
> > what JQuery code does. IE has memory leak problems (or at lest older
> > versions of it do), but what does "non-native events" mean, and how is
> > this going to prevent the memory leaks?
>
> The `elem` property could be used in `call` to resolve context to `elem`
> and could deleted later in the "remove" method.
>
> | function getBoundCallback(o, cb) {
> |   // no binding for window, because:
> |   // 1) context is already global and
> |   // 2) removing onunload handlers is skipped (see cleanUp);
> |   if (o === window)
> |     return cb;
> |   function bound(ev) {
> |     bound.original.call(bound.context, ev || window.event);
> |   }
> |   bound.original = cb;
> |   bound.context = o;
> |   cb = o = null;
> |   return bound;
> | }
>
> And in the `remove` method, I call removeFromCallstack which deletes the
> properties `context` `original` from the `bound` method.
>
> | function removeFromCallStack(callStack, callback) {
> |   var cb, i, len;
> |   for (i = 0, len = callStack.length; i < len; i++) {
> |     cb = callStack[i];
> |     if ((cb.original || cb) === callback) {
> |       delete cb.original;
> |       delete cb.context;
> |       return callStack.splice(i, 1)[0];
> |     }
> |   }
> |   return null;
> | }
>
> > Possibly the idea is that if the variable - elem - where referenced in
> > the - jQuery.event.handle.apply( ... - line above, and not nulled at
> > the end of this method, then there would be an obvious circular chain
> > of reference, which there would be. But what follows rather negates
> > any effort taken to avoid that circle.
>
> Right, they null it, and then save the reference to `elem` as a property
> to the function, creating a circular reference.
>
> The chain can be broken by deleting the `elem` property in the remove
> method.
>
> [...]
>
>
>
> > Outside of JQuery you can do whatever you like to avoid the memory
> > leak-inducing circular chains of references, but JQuery creates them
> > for you when you use its - bind - method. Now the question is whether
> > JQuery cleans these circular chains of reference up on its own, or
> > whether you are going to have to take some remedial action to remove
> > bound methods; time to "slog through jQuery's code again".
>
> I see near the bottom of `remove`:
> | if ( jQuery.isEmptyObject( events ) ) {
> |  var handle = elemData.handle;
> |  if ( handle ) {
> |    handle.elem = null;
> |  }

The chain will be broken on remove anyway. You have to handle the
case where the application does not remove the listeners.

The proper solution is: don't create such circular references in the
first place. That's what I went with.