Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #9466 (closed defect: fixed)

Opened 8 months ago

Last modified 5 days ago

[PATCH] Event memory leaks on IE6

Reported by: na43251 Assigned to: sam
Priority: high Milestone:
Component: Prototype Version: edge
Severity: major Keywords: event
Cc:

Description

i think Protototype Event.destroyCache doesn`t do what it should. on each request memory increses +1M and scripts turns slower and slower

Prototype: 1.6.0_rc0 and trunk(r7404) IE version: 6.0.2900.2180.xpsp2_rtm.040803-2158

i tested also with Drip (http://outofhanwell.com/ieleak/) and it showed memory leaks too.

IE7 and FF2 is ok.

Attachments

index.html (0.6 kB) - added by na43251 on 09/03/07 12:57:52.
Leak example
ie6fix.patch (0.6 kB) - added by na43251 on 09/04/07 14:11:10.
ie6leak.htm (0.8 kB) - added by micheldavid on 01/27/08 15:22:41.
aggressive bug example
event_ie_leak_fix.diff (5.1 kB) - added by jdalton on 03/31/08 19:57:08.
Only removes elements that are observing, optimize wrapper lookup.

Change History

09/03/07 10:20:27 changed by Tobie

FYI Drip isn't a trustful tool, it gives a lot of false positives.

09/03/07 10:32:27 changed by Tobie

could you provide us a code sample which leaks memory so we can test it? That would be very much appreciated.

09/03/07 12:45:06 changed by na43251

this example gives me 1.6.0_rc0: +1M memory usage after each request, 1.5.1.1: ~constant memory usage

09/03/07 12:57:52 changed by na43251

  • attachment index.html added.

Leak example

(follow-up: ↓ 7 ) 09/04/07 10:55:15 changed by na43251

this patch works for me, ie6 performs much much better

as i understand, we cant get attached elements with the new Event API for Event.cache so in my patch i checks every DOM element for _eventID and stops observing them all.

the result is somethnig like in 1.5.1.1 when Event.unloadCache did Event.stopObserve on all observers before nullifying.

09/04/07 14:11:10 changed by na43251

  • attachment ie6fix.patch added.

01/27/08 15:20:17 changed by micheldavid

I have a lot of Event.observe in my web system, and this has been killing my IE6 users. I posted to the prototype group http://groups.google.com/group/prototype-core/browse_frm/thread/c2456d26913c7178 but got no answers. I think this is more than a normal priority bug, since it has been holding me from update to version 1.6... and probably causing a hazard in a lot of other web pages.

01/27/08 15:22:41 changed by micheldavid

  • attachment ie6leak.htm added.

aggressive bug example

03/29/08 17:57:13 changed by jdalton

  • priority changed from normal to high.
  • severity changed from normal to major.

(in reply to: ↑ 4 ) 03/30/08 01:12:48 changed by jdalton

Replying to na43251

Your patch is a bit to brute force for me, it iterates over a whole document just to remove possibly only a few observers.

The patch I have attached only removes the elements that are observing. I have also optimized the wrapper lookup so it spends less time looking up a wrapper if it already has it.

It passes the unit tests as well :)

03/30/08 01:16:13 changed by jdalton

Also it reduces the complexity of the getEventID() method by removing a condition for the arguments.callee and has the counter start at 1 instead of 2.

03/30/08 01:17:23 changed by jdalton

  • summary changed from Event memory leaks on IE6 to [PATCH] Event memory leaks on IE6.

03/30/08 01:20:18 changed by jdalton

I rolled in the 1 line patch from this ticket as well: http://dev.rubyonrails.org/ticket/11453

03/30/08 03:10:37 changed by kangax

Yep, the first attached file demonstrates leak quite aggressively and shows ~2M/sec increase in IE6. IE7 seems to be unaffected. Simple removal of event handlers from observed elements solves the issue:

destroyCache: function() {

  $A(document.getElementsByTagName('*')).each(function(element) {
    if (!element._prototypeEventID) return;
    Event.stopObserving(element);
  })
  
  ...

}

(follow-up: ↓ 13 ) 03/30/08 03:51:23 changed by kangax

I think "brute-force" approach is more than enough in this case. unloadCache is executed once on unload. It doesn't seem to be a critical part of the program. I'm not sure if creating an instance of Wrapper for each event handler is a better approach. Moreover, keeping reference to element in a wrapper could introduce circular references between this.handler and this.element

(in reply to: ↑ 12 ) 03/30/08 05:09:11 changed by jdalton

Replying to kangax:

Do removed elements that at one time where in the dom and had observers contribute to the memory leak?

If "yes", then the "brute-force" method will miss those.

I don't by the circular reference argument. Prototype 1.5+ stored references to the element in its implementation and it didn’t suffer from memory leaks.

I don't buy the Wrapper instance argument either. I did some benchmarking using console.time()/1000+ iterations and the speeds where equiv.

03/30/08 05:22:49 changed by kangax

The initialize function of a Wrapper "class" defines another function - the one stored in a handler property. This handler function has this.element in it's closure - therefore circular reference is created. I'm not an expert in such things but it seems that proposed pattern could lead to even more problems : )

(follow-up: ↓ 16 ) 03/30/08 05:32:36 changed by jdalton

crap :D
updating patch to take care of that.
Event Prototype 1.5 set the element to null.

(in reply to: ↑ 15 ) 03/30/08 05:33:59 changed by kangax

Replying to jdalton:

crap :D
updating patch to take care of that.
Event Prototype 1.5 set the element to null.

told ya : )

03/31/08 17:50:44 changed by jdalton

related (leaks when element, that had an event observer, is destroyed): http://dev.rubyonrails.org/ticket/11371

03/31/08 19:57:08 changed by jdalton

  • attachment event_ie_leak_fix.diff added.

Only removes elements that are observing, optimize wrapper lookup.

05/07/08 19:10:21 changed by jdalton

  • status changed from new to closed.
  • resolution set to fixed.