Toon posts:

Voorkomen & oplossen van memory leaks in MSIE

Pagina: 1
Acties:
  • 261 views sinds 30-01-2008
  • Reageer

Verwijderd

Topicstarter
Nog niet eerder uitgebreid behandeld, maar wel een topic op zich waard. Microsoft Internet Explorer (en in mindere mate Mozilla) heeft last van memory leaks in Javascript, die voorkomen bij gebruik van DOM, en ActiveX.

De gemiddelde gebruiker weet dit niet, developers die dagelijks aan website gerelateerde projecten werken en veelvuldig gebruik maken van Javascript wel.

Het verwijderen van elementen met childs, zonder het eerst verwijderen van de childs resulteerd bijvoorbeeld in het aanwezig blijven van deze childs in het geheugen. Resultaat is dat al deze childs eerst moeten worden opgeruimd, alvorens het element op te ruimen.

Voor het gemiddelde image swap script is dit niet echt een probleem. De geheugenlekken zullen niet al te bijzonder zijn.

Het wordt wel een probleem, zodra je, zoals tegenwoordig mogelijk, gebruik gaat maken van de voordelen van Javascript op een grotere basis. Navigatie structuren via XML, complete UI componenten etc. Je gaat dan al snel geheugenlekken tegenkomen.

Met dit topic hoop ik dat er wat meer duidelijkheid komt over het herkennen, opsporen, en voorkomen van deze lekken.

De oorzaak van het lekker in MSIE is de manier van garbage collection in MSIE. Javascript gebruik “mark and sweep” welke immuun is voor circular references. De MSIE is alleen immuun voor circular references die verwijzen naar pure JS objecten. (geen ActiveX of DOM objects).
http://msdn.microsoft.com...es/02/04/web/default.aspx
Q Why doesn't the garbage collector release a reference to an ActiveX® object when the page is refreshed? I know JScript utilizes lazy garbage collection, but in this case memory allocated is never released when you refresh the page. Futhermore, when you refresh the page, memory comsumption grows because of the new ActiveX object that's created."

"A The problem is that it's Internet Explorer that holds the reference to the function which in turn holds a reference to the ActiveX object that isn't being released.
For performance reasons, Internet Explorer does not kill the DOM nodes until either you navigate to a different page or you close the browser. Refreshing the current page will not kill the nodes. The problem is not that the garbage collector is lazy—the problem is that it's not immune to circular reference chains which contain objects not created by the JScript engine. The browser object model is created by the browser, not by the language engine."
Het resultaat is dus dat je alle referenties handmatig moet verbreken tussen JS objects en DOM/ActiveX objects.


Geheugenlekken:

Als je de DOM form, en element objects gaat extenden met je eigen methods. Properties toevoegen, zelfs als ze groot zijn, veroorzaakt geen geheugenlekken.

Zodra je XML/XSLT of XSD gaat gebruiken, wordt je geheugenlek 2x tot 3x zo groot als normaal.

Javascripts embedded in je pagina, met document.write() calls lekken. Deze zijn op te lossen door deze te vervangen met document.createElement en document.createTextNode()

DOM objects aanmaken, en hier event handlers aanhangen. De event handlers lekker. Een oplossing hiervoor schijnt het setten van een null value op onunload te zijn.

In plaats van dit:
mijnObject.elementReference = document.getElementById("someReference") ;

Doe dit:
mijnObject.elementReference = "someReference";
function something(obj) {
var elm = document.getElementById(obj.elementReference) ;
}

Voor het verwijderen van referenties:

Voor:
var o = {};
var el = document.getElementById(sId);
o.element = el;
el.jsObject = o;

Kan je zoiets gebruiken:
o.element.jsObject = null;
o.element = null;


Spui je tips, ervaringen :) Er is op het internet niet bijzonder veel te vinden over dit onderwerp, en het bestaat meestal uit wat losse flodders.

  • BtM909
  • Registratie: Juni 2000
  • Niet online

BtM909

Watch out Guys...

Het verwijderen van references was ik ook al achter gekomen, dmv:

JavaScript:
1
o.element.jsObject = null;

Wat ik tegenwoordig ook wel eens doe, mits de applicatie het toelaat, is een harde refresh.
Volgens mij liep crisp hier ook tegenaan, met de GoT Tracker.


Daarnaast maken wij regelmatig hevig gebruik van ActiveX controls, maar ben er nog niet tegenaan gelopen dat IE uit het geheugen loopt. :? Heb je hier toevallig een test-case van?

Ace of Base vs Charli XCX - All That She Boom Claps (RMT) | Clean Bandit vs Galantis - I'd Rather Be You (RMT)
You've moved up on my notch-list. You have 1 notch
I have a black belt in Kung Flu.


  • Clay
  • Registratie: Oktober 1999
  • Laatst online: 22-06 13:51

Clay

cookie erbij?

Wat betreft de events kan het kan idd vrij treurig oplopen, dit bijvoorbeeld lekt (bij mij) tussen de 200K en 400K per refresh:

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Ding() {
    var div = document.createElement('div');
    div.appendChild(document.createTextNode('test'));
    this.el = document.body.appendChild(div);

    this.el.onmouseover = function() {
        this.style.backgroundColor = '#f0f0f0';
    }

    this.el.onmouseout = function() {
        this.style.backgroundColor = 'white';
    }
}

window.onload = function() {
    for(var i=0; i<200; i++) {
        new Ding();
    }
}


Elk Ding() krijgt ook anonieme functions zo, maar dat wordt dus idd niet opgeruimd. Wat daartegen inderdaad werkt is het eruit halen van die functies, en er een handler aanhangen, ala:

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function Ding() {
    var div = document.createElement('div');
    div.appendChild(document.createTextNode('test'));
    this.el = document.body.appendChild(div);

    this.el.onmouseover = divMouseover;
    this.el.onmouseout = divMouseout;
}

    function divMouseover() {
        this.style.backgroundColor = '#f0f0f0';
    }

    function divMouseout() {
        this.style.backgroundColor = 'white';
    }

window.onload = function() {
    for(var i=0; i<200; i++) {
        new Ding();
    }
}


Zo maakt een refresh dus niet meer uit.

Instagram | Flickr | "Let my music become battle cries" - Frédéric Chopin


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 20:27

crisp

Devver

Pixelated

met activeX objecten zet ik meestal de reference niet op null, maar delete ik 'm helemaal - ik meen dat dat vnl in Mozilla enorm scheelde.
De GoT Tracker draait bij mij op de desktop en ik merk zelfs na enkele dagen niet echt dat 'ie meer geheugen vreet. Ik zal het echter eens in de gaten houden...

Intentionally left blank


Verwijderd

Topicstarter
crisp schreef op 17 oktober 2003 @ 12:33:
met activeX objecten zet ik meestal de reference niet op null, maar delete ik 'm helemaal - ik meen dat dat vnl in Mozilla enorm scheelde.
De GoT Tracker draait bij mij op de desktop en ik merk zelfs na enkele dagen niet echt dat 'ie meer geheugen vreet. Ik zal het echter eens in de gaten houden...
Heb je nog bepaalde workarounds moeten gebruiken om geheugen lekken te beperken?

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 20:27

crisp

Devver

Pixelated

Verwijderd schreef op 17 October 2003 @ 12:49:
[...]
Heb je nog bepaalde workarounds moeten gebruiken om geheugen lekker te beperken?
Niet dat ik me kan herinneren eigenlijk. Dat ding trekt zo'n 40KB per 5 minuten binnen, dus ik denk dat dat ook de max memleak kan zijn - nu zal ik dat met een half gig geheugen natuurlijk ook niet zo snel merken.

In lemmings gebruik ik ook handlers op de manier zoals Clay illustreerd, maar daar wordt aan het einde van een spel natuurlijk ook weer naar een andere pagina genavigeerd.

Intentionally left blank


Verwijderd

Ik heb wel eens gehoord dat het gebruik van filters in IE en de DOM ook veel geheugen lekt. Weet er verder niet veel van.

Verwijderd

hier
staan ook nog veel interessante links. Hoop dat je er wat aan hebt.

Verwijderd

Topicstarter
Verwijderd schreef op 17 oktober 2003 @ 13:06:
Ik heb wel eens gehoord dat het gebruik van filters in IE en de DOM ook veel geheugen lekt. Weet er verder niet veel van.
Dat klopt zowiezo. Ik heb zo'n notifier ding net als MSN in dhtml gemaakt voor iets wat nog in ontwikkeling is. Die moet vervolgens over een pagina sliden, naar boven, waar een filter:gradient in zit.

Daar wordt je dus niet vrolijk van hoor.

Verwijderd

Topicstarter
Clay schreef op 17 oktober 2003 @ 12:14:
Wat betreft de events kan het kan idd vrij treurig oplopen, dit bijvoorbeeld lekt (bij mij) tussen de 200K en 400K per refresh:

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Ding() {
    var div = document.createElement('div');
    div.appendChild(document.createTextNode('test'));
    this.el = document.body.appendChild(div);

    this.el.onmouseover = function() {
        this.style.backgroundColor = '#f0f0f0';
    }

    this.el.onmouseout = function() {
        this.style.backgroundColor = 'white';
    }
}

window.onload = function() {
    for(var i=0; i<200; i++) {
        new Ding();
    }
}


Elk Ding() krijgt ook anonieme functions zo, maar dat wordt dus idd niet opgeruimd. Wat daartegen inderdaad werkt is het eruit halen van die functies, en er een handler aanhangen, ala:

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function Ding() {
    var div = document.createElement('div');
    div.appendChild(document.createTextNode('test'));
    this.el = document.body.appendChild(div);

    this.el.onmouseover = divMouseover;
    this.el.onmouseout = divMouseout;
}

    function divMouseover() {
        this.style.backgroundColor = '#f0f0f0';
    }

    function divMouseout() {
        this.style.backgroundColor = 'white';
    }

window.onload = function() {
    for(var i=0; i<200; i++) {
        new Ding();
    }
}


Zo maakt een refresh dus niet meer uit.
Ik wil dit nog even verduidelijken :)
this.el.onmouseover = function() {
this.style.backgroundColor = '#f0f0f0';
}
resulteerd in andere woorden in:

this.el.attachEvent("onmouseover", function() {this.style.backgroundColor= '#f0f0f0';};

De heeft als resultaat dat er geen detachEvent door de browser kan worden aangeroepen, omdat er geen referentie aanwezig is, want er is direct een functie ge-attached.

Dit is dus wel het geval met de workaround zoals Clay die voorstelt.
this.el.attachEvent("onmouseover", divMouseover);

Hier kan vervolgens met this.el.detachEvent("onmouseover", divMouseover);

De eventhandler weer netjes opgeruimd worden omdat er een referentie naar divMouseover is.

Zo komt het dus dat de browser geen geheugen vrijmaakt, hij kan geen referenties vinden, en zodoende valt er even niets te detachen.

Verwijderd

Topicstarter
Ik word een beetje geschift ondertussen. De aanleiding van dit topic was om meer informatie te krijgen over geheugen lekken, mede omdat ik er in een component wat ik aan het ontwikkelen ben, erg veel last heb van een lastig lek.

Ik heb alle situaties ontweken die lijden tot geheugen lekken, alle workaround toegepast, zet alles netjes op null..etc..etc.. en toch hou ik bij elke refresh van de pagina een verhoging van het geheugen van +/- 100kb.

Als iemand wat van dit onderwerp afweet, zou die dan eventjes een kort blikje willen werpen op dit probleem? Ik ben bijna klaar met het component wat ik daarna als freeware wil releasen, maar het enige wat ik er niet uitkrijg zijn die geheugenlekken.

http://members.chello.nl/.../treewidget/treeview.html

Suggesties zijn altijd welkom, maar in eerste instantie wil ik af van die memory leaks.

Verwijderd

Topicstarter
Zojuist ontdekt. Voor IE is er een undocumented feature onderdeel van het window object:
CollectGarbage();

Je kunt dus bij refreshes van een pagina de nodige zooi verwijderen dmv de onunload method op de body :)

function flush() {
object1 = null;
object2 = null;
CollectGarbage()
}

<body onunload="flush()">


Cyclic references zoals in mijn startpost genoemd, zorgen ook voor memory leaks. Een voorbeeld hiervan is:

var p = new myObject();
var c = new myObject();
p.child = c;
c.parent = p;


Een workaround hiervoor is bijv:

var objRefs = [];
var p = new myObject();
var c = new myObject();
regObj(p,"child",c);
regObj(c,"parent",p);

function myObject() {return document.createElement("div");}

function regObj(o,s,p) {regObjs[regObjs.length] = [o,s]; o[s] = p; return p;}

function onUnload() {
for (var i=0;i<regObjs.length;i++) {regObjs[i][0][regObjs[i][1]] = null; regObjs[i][0] = null;}
CollectGarbage();
}

<body onunload="onUnload();">

Verwijderd

Topicstarter
Heb Microsoft maar gemailed over een issue die ik heb. Hoe moet je in vredesnaam onder cyclic references uitkomen als je een applicatie dmv JS OOP op wilt zetten :?

Echt belachelijk deze zooi.

  • BtM909
  • Registratie: Juni 2000
  • Niet online

BtM909

Watch out Guys...

Verwijderd schreef op 19 oktober 2003 @ 17:07:
Heb Microsoft maar gemailed over een issue die ik heb. Hoe moet je in vredesnaam onder cyclic references uitkomen als je een applicatie dmv JS OOP op wilt zetten :?

Echt belachelijk deze zooi.
Heb je al reactie gehad?

Ace of Base vs Charli XCX - All That She Boom Claps (RMT) | Clean Bandit vs Galantis - I'd Rather Be You (RMT)
You've moved up on my notch-list. You have 1 notch
I have a black belt in Kung Flu.


Verwijderd

Vegeet het maar, daar krijg je geen antwoord op. \o/ voor MS :(

Verwijderd

Topicstarter
Ik heb nog geen antwoord gekregen, maar heb al een besparing van 50kb weten te krijgen, door echt alle, maar dan ook alle references op null te zetten. Het kan nog meer, omdat ik niet recursief in de treeview alles op null zet. Dus dat ga ik nog doen, en dan moet ik dus vanaf het diepste niveau omhoog kruipen naar de node die wordt ge-removed, en elke node op null zetten.

Het is belachelijk veel werk om de garbage collector op de manier een duw te geven, maar er zit niets anders op.

Ik krijg bijv. alleen al bij createElement en appendChild een geheugen increase erbij waar je niet goed van wordt.

[ Voor 11% gewijzigd door Verwijderd op 21-10-2003 11:59 ]


  • GrimaceODespair
  • Registratie: December 2002
  • Laatst online: 13:41

GrimaceODespair

eens een tettenman, altijd ...

Verwijderd schreef op 21 October 2003 @ 11:19:
Vegeet het maar, daar krijg je geen antwoord op. \o/ voor MS :(
Ze krijgen zo waarschijnlijk ook maar 1000 mails per dag B) Wat niet wegneemt dat het hier toch wel over grove tekortkomingen gaat.

Maareuh, Gordijnstok, handig topic. Misschien kun je de layout van de topicstart wat aanpassen om het overzichtelijker te maken. Altijd leuk om dit soort resources bij de hand te hebben als je tijdens het developen weer eens ergens op stukloopt.

Het is toch wel een 'grappig' idee, dat je in een omgeving met garbage collection alsnog je eigen rotzooi moet opruimen. Een beetje zoals dat ik mijn eigen kamer zou opruimen, omdat mijn moeder dat niet goed zou doen (of andersom) :+

[ Voor 18% gewijzigd door GrimaceODespair op 21-10-2003 12:07 ]

Wij onderbreken deze thread voor reclame:
http://kalders.be

Pagina: 1