[JS / IE6] Anonymous functions en memory leaks*

Pagina: 1
Acties:

  • vorlox
  • Registratie: Juni 2001
  • Laatst online: 02-02-2022

vorlox

I cna ytpe 300 wrods pre miute

Topicstarter
Ik zit wat te rommelen met een javascript leak detector en natuurlijk komen er tal van leaks naar boven.

Nu heb ik op het web volgens mij alle JS sites wel gehad maar nu zit ik toch nog met de volgende vraag:

Ik gebruik zelf altijd een JS opbouw zoals onderstaand
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function MyObject(container)
{
    //Prop
    this.Name = 'Test';
    this.Container = document.getElementById(container);
    
    //Build
    this.build();
}

MyObject.prototype.build = function()
{
    var _self = this;
    var oDiv = document.createElement('div');
    oDiv.innerHTML = 'Divje';
    oDiv.onclick = function() { _self.handleClick(); }
    this.Container.appendChild(oDiv);
    oDiv = null;
}

MyObject.prototype.handleClick = function()
{
    alert(this.Name); //Geeft "Test" terug
}


Echter nu zeurt die JS leak detector dus dat dit anonymous functions zijn en dus leaks
Maar er moet toch een niet leakende manier zijn om dit te doen.?

Deze code werkt niet
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function MyObject1(container)
{
    //Prop
    this.Name = 'Test';
    this.Container = document.getElementById(container);
    
    //Build
    this.build();
}

MyObject1.prototype.build = function()
{
    var _self = this;
    var oDiv = document.createElement('div');
    oDiv.innerHTML = 'Divje';
    oDiv.onclick = _self.handleClick;
    this.Container.appendChild(oDiv);
    oDiv = null;
}

MyObject1.prototype.handleClick = function()
{
    alert(this.Name); //Geeft "Undefined" terug
}


Ter info ik gebruik Microsoft GPD Europe Javascript memory leaks detector

[ Voor 8% gewijzigd door vorlox op 04-06-2008 17:23 ]


  • Wolfboy
  • Registratie: Januari 2001
  • Niet online

Wolfboy

ubi dubium ibi libertas

Je kan een functie gewoon direct een naam geven om dit probleem op te lossen, dan krijg je dus zoiets:

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function MyObject(container)
{
    //Prop
    this.Name = 'Test';
    this.Container = document.getElementById(container);
    
    //Build
    this.build();
}

MyObject.prototype.handleClick = function my_object_handle_click()
{
    alert(this.Name); //Geeft "Test" terug
}

MyObject.prototype.build = function my_object_build()
{
    var _self = this;
    var oDiv = document.createElement('div');
    oDiv.innerHTML = 'Divje';
    oDiv.onclick = MyObject.prototype.handleClick;
    this.Container.appendChild(oDiv);
    oDiv = null;
}

Blog [Stackoverflow] [LinkedIn]


  • Erkens
  • Registratie: December 2001
  • Niet online

Erkens

Fotograaf

Wolfboy schreef op woensdag 04 juni 2008 @ 17:10:
Je kan een functie gewoon direct een naam geven om dit probleem op te lossen, dan krijg je dus zoiets:

JavaScript:
1
2
3
4
5
6
7
MyObject.prototype.handleClick = function my_object_handle_click()
{
}

MyObject.prototype.build = function my_object_build()
{
}
Wat je nu doet is dat je die functies een naam geeft waardoor deze de global scope vervuilen, terwijl dat niet nodig is want je kan die functie al aanroepen via MyObject :)
Nu weet ik niet welk tooltje vorlox precies heeft gebruikt, maar ik kan me niet voorstellen dat deze manier van werken "slecht" is.

  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 05-09 14:39

_Thanatos_

Ja, en kaal

Die zogenaamde leaks zijn dikke onzin. Een javascript engine heeft een garbage collector, dus het is onmogelijk om lekken te hebben. Dingen die uit scope raken worden vanzelf collected. Als je je javascript op correctheid wilt controleren, is JSLint een veel betere tool. En het loont om dan "Disallow undefined variables" aan te vinken voordat je de check uitvoert.

日本!🎌


Verwijderd

Da's dikke onzin, leaks zijn geen onzin.

http://msdn.microsoft.com/en-us/library/bb250448(VS.85).aspx

  • vorlox
  • Registratie: Juni 2001
  • Laatst online: 02-02-2022

vorlox

I cna ytpe 300 wrods pre miute

Topicstarter
_Thanatos_ schreef op woensdag 04 juni 2008 @ 20:37:
Die zogenaamde leaks zijn dikke onzin. Een javascript engine heeft een garbage collector, dus het is onmogelijk om lekken te hebben. Dingen die uit scope raken worden vanzelf collected. Als je je javascript op correctheid wilt controleren, is JSLint een veel betere tool. En het loont om dan "Disallow undefined variables" aan te vinken voordat je de check uitvoert.
Uh ja hoor daarom is IE ook na een paar uur 90 MB groot..omdat de garbage collector alles opruimt.

idd ja je hebt helemaal gelijk nou bedankt voor de tip hoor...veel geluk in jouw wereldje

  • Wolfboy
  • Registratie: Januari 2001
  • Niet online

Wolfboy

ubi dubium ibi libertas

Erkens schreef op woensdag 04 juni 2008 @ 17:18:
[...]

Wat je nu doet is dat je die functies een naam geeft waardoor deze de global scope vervuilen, terwijl dat niet nodig is want je kan die functie al aanroepen via MyObject :)
Nu weet ik niet welk tooltje vorlox precies heeft gebruikt, maar ik kan me niet voorstellen dat deze manier van werken "slecht" is.
Voor zover ik weet heb je helemaal gelijk, maar als zijn tooltje named functies wil, wat imho sowieso wel een goed idee is aangezien debuggen ook eenvoudiger is (bij firebug stacktraces bijvoorbeeld), dan is dat te regelen.

@vorlox: IE heeft sowieso ladingen memory leaks, een simpele replacechild levert al flinke memory leaks op bijvoorbeeld.

Blog [Stackoverflow] [LinkedIn]


  • Erkens
  • Registratie: December 2001
  • Niet online

Erkens

Fotograaf

Wolfboy schreef op woensdag 04 juni 2008 @ 22:32:
Voor zover ik weet heb je helemaal gelijk, maar als zijn tooltje named functies wil, wat imho sowieso wel een goed idee is aangezien debuggen ook eenvoudiger is (bij firebug stacktraces bijvoorbeeld), dan is dat te regelen.
Als je het puur alleen voor debug doet, dan denk ik dat het toch handiger is om het niet te doen, alleen al de vervuiling van je globalspace (wat dus ook weer geheugen verbruikt :+ ). Verder kan je de stacktraces in firebug ook nog wel volgen zonder die namen, true, het is iets meer moeite, maar niet zo erg ingewikkeld dat het opweegt tegen de nadelen.

  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 22:12
Of het memory-leak-technisch gezien beter is zou ik niet durven zeggen, maar een alternatieve manier om te bereiken wat je wil is door function binding:
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Function.prototype.bind = function(object)
{
    var _method = this;
    return function() { return _method.apply(object, arguments); }
}

//en dan in build:
MyObject.prototype.build = function()
{
    var _self = this;
    var oDiv = document.createElement('div');
    oDiv.innerHTML = 'Divje';
    oDiv.onclick = this.handleClick.bind(this);
    this.Container.appendChild(oDiv);
    oDiv = null;
}

[ Voor 0% gewijzigd door T-MOB op 04-06-2008 23:00 . Reden: kleurtjes zijn stuq! Boe, nog steeds ]

Regeren is vooruitschuiven


  • Wolfboy
  • Registratie: Januari 2001
  • Niet online

Wolfboy

ubi dubium ibi libertas

Erkens schreef op woensdag 04 juni 2008 @ 22:52:
[...]

Als je het puur alleen voor debug doet, dan denk ik dat het toch handiger is om het niet te doen, alleen al de vervuiling van je globalspace (wat dus ook weer geheugen verbruikt :+ ). Verder kan je de stacktraces in firebug ook nog wel volgen zonder die namen, true, het is iets meer moeite, maar niet zo erg ingewikkeld dat het opweegt tegen de nadelen.
Ik kan het mis hebben maar een class functie blijft toch gewoon een class functie? Voor zover ik weet komen die niet apart in je globalspace hoor.

@T-MOB: die functies zijn toch nog steeds unnamed? Zowel build als bind hebben geen naam.

Blog [Stackoverflow] [LinkedIn]


  • Erkens
  • Registratie: December 2001
  • Niet online

Erkens

Fotograaf

Wolfboy schreef op woensdag 04 juni 2008 @ 23:24:
[...]
Ik kan het mis hebben maar een class functie blijft toch gewoon een class functie? Voor zover ik weet komen die niet apart in je globalspace hoor.
Nu begin ik aan mezelf te twijfelen...
Ik ga het morgen even testen/nazoeken als ik tijd heb :)

  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 05-09 14:39

_Thanatos_

Ja, en kaal

Microsoft geeft in dat artikel toe dat hun browser lekt, niet dat javascript als taal in de basis lek is. Een browser als Opera, Firefox of Safari hebben geen/minder last van lekken.
Uh ja hoor daarom is IE ook na een paar uur 90 MB groot..omdat de garbage collector alles opruimt.
Net als die andere drie browser doet MSIE het ook: cachen. Niet alleen op disk, maar ook in het geheugen. Natuurlijk zal er bij MSIE wel geheugenlekken bijzitten, maar over het algemeen zijn dat wel bugs die MS fixt nadat ze gevonden zijn.

Een geheugenlek in een non-native sandboxed taal en framework. Dat KAN gewoon niet. Je kunt nml geen geheugen vrijgeven, dus de engine MOET er wel voor zorgen dat alles automagisch opgeruimt wordt. Als jij graag zo wilt programmeren dat dingen hardhandig vrijgegeven worden - zo aan het artikel te zien zelfs ten koste van de kwaliteit van je code - doe het vooral, maar het is echt nutteloos.

Maargoed, misschien loont het om erbij te zeggen dat de "lekken" die je kunt hebben in javascript, eigenlijk geen lekken zijn, maar objecten die binnen scope keer op keer redefined worden, anonymously. Dat MAG geen probleem zijn, maar dat is het in sommige (1) browser kennelijk wel. Zorg dus gewoon dat je een functie 1 keer definieert. Lijkt me voldoende. Maar dan nog, rekening gaan met IE6-bugs die je in de praktijk niet eens tegenkomt. Doe normaal zeg :?

日本!🎌


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22:10

.oisyn

Moderator Devschuur®

Demotivational Speaker

_Thanatos_ schreef op woensdag 04 juni 2008 @ 20:37:
Die zogenaamde leaks zijn dikke onzin. Een javascript engine heeft een garbage collector, dus het is onmogelijk om lekken te hebben.
Je praat poep. Garbage collection is geen garantie voor lekvrije software. Als het framework namelijk referenties houdt naar jouw objecten terwijl je die zelf 'vergeet', dan blijven ze gewoon in het geheugen. Memory en resource leaks heb je ook gewoon in GC'd omgevingen als Java en .Net. Daarom kennen die zogenaamde weak references, die niet als daadwerkelijke reference telt voor de GC (en null worden zodra het object is opgeruimd), zodat het toch mogelijk is om langlopende references naar objecten te maken zonder hun lifetime te beinvloeden.

[ Voor 19% gewijzigd door .oisyn op 05-06-2008 01:45 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Wolfboy
  • Registratie: Januari 2001
  • Niet online

Wolfboy

ubi dubium ibi libertas

_Thanatos_ schreef op donderdag 05 juni 2008 @ 01:01:
Een geheugenlek in een non-native sandboxed taal en framework. Dat KAN gewoon niet. Je kunt nml geen geheugen vrijgeven, dus de engine MOET er wel voor zorgen dat alles automagisch opgeruimt wordt. Als jij graag zo wilt programmeren dat dingen hardhandig vrijgegeven worden - zo aan het artikel te zien zelfs ten koste van de kwaliteit van je code - doe het vooral, maar het is echt nutteloos.
Het is absoluut niet nutteloos, Internet Explorer heeft een paar _flinke_ geheugenlekken er in zitten, al ben ik met je eens dat je er niet op zou moeten letten, het moet toch zeker wel.
Ga voor de lol maar eens een hele lading events setten op je pagina (grote functies in de events) en dan de pagina een stuk of 100 keer refreshen, je zal het geheugengebruik flink omhoog zien gaan.
Maargoed, misschien loont het om erbij te zeggen dat de "lekken" die je kunt hebben in javascript, eigenlijk geen lekken zijn, maar objecten die binnen scope keer op keer redefined worden, anonymously. Dat MAG geen probleem zijn, maar dat is het in sommige (1) browser kennelijk wel. Zorg dus gewoon dat je een functie 1 keer definieert. Lijkt me voldoende. Maar dan nog, rekening gaan met IE6-bugs die je in de praktijk niet eens tegenkomt. Doe normaal zeg :?
Het is niet alleen een IE6 bug, in IE7 is het probleem ook zeker aanwezig, en ook Firefox is verre van lek-vrij (hetzij minder ernstig), als je de events _niet_ verwijderd dan zal je geheugengebruik (bij IE iig.) flink zien oplopen, ook al zou dit bij het reloaden/wegklikken van een pagina moeten verdwijnen. Naast events zitten er overigens ook nog geheugenlekken in removeChild en replaceChild IIRC, garbage collection is een leuk concept maar niet in alle gevallen goed genoeg uitgevoerd.

En verder, met .oisyn :)

Blog [Stackoverflow] [LinkedIn]


Verwijderd

T-MOB schreef op woensdag 04 juni 2008 @ 22:56:
Of het memory-leak-technisch gezien beter is zou ik niet durven zeggen, maar een alternatieve manier om te bereiken wat je wil is door function binding:
JavaScript:
1
2
3
4
5
Function.prototype.bind = function(object)
{
    var _method = this;
    return function() { return _method.apply(object, arguments); }
}
Ik heb nooit begrepen waarom zo'n bind() methode duidelijker of beter zou zijn dan gewoon direct apply() of call() toe te passen op een functie.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22:10

.oisyn

Moderator Devschuur®

Demotivational Speaker

Maar je vergeet het cruciale stuk te quoten:
JavaScript:
1
    oDiv.onclick = this.handleClick.bind(this);

Het idee van function binding (in het algemeen, niet per se javascript) is bepaalde parameters voor functie van tevoren invullen, zodat je een functie terug krijgt met als parameters de overige oningevulde parameters - feitelijk een vorm van currying dus.

Het object waar je de functie op aanroept moet je zien als een impliciete parameter. Wat hier dus gebeurt is dat je een losse functie terugkrijgt die je aan kunt roepen zonder dat je daar een object voor hoeft te zetten, terwijl uiteindelijk toch de 'this' goed wordt ingesteld. Oftewel, bij het onclick event wordt de functie aangeroepen op een instance van MyObject, ipv een instance van het div element waar het event op gezet is. Het direct aanroepen van apply() of call() is dus helemaal niet van toepassing.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 05-09 14:39

_Thanatos_

Ja, en kaal

Garbage collection is geen garantie voor lekvrije software. Als het framework namelijk referenties houdt naar jouw objecten terwijl je die zelf 'vergeet', dan blijven ze gewoon in het geheugen.
Totdat de pagina uit het geheugen verdwijnt, en daarmee al het script van die pagina buiten scope raakt. Het nagenoeg enige dat nog in scope is, is window.name, maar die verdwijnt ook als het window/tab gesloten wordt. Dat is de theorie. Als de browser dit niet goed implementeert, dan is het flauwekul om je in allerlei rare bochten te wringen, terwijl de maker van de browser het gewoon moet fixen.

日本!🎌


  • NetForce1
  • Registratie: November 2001
  • Laatst online: 00:12

NetForce1

(inspiratie == 0) -> true

_Thanatos_ schreef op donderdag 05 juni 2008 @ 14:23:
[...]

Totdat de pagina uit het geheugen verdwijnt, en daarmee al het script van die pagina buiten scope raakt. Het nagenoeg enige dat nog in scope is, is window.name, maar die verdwijnt ook als het window/tab gesloten wordt. Dat is de theorie. Als de browser dit niet goed implementeert, dan is het flauwekul om je in allerlei rare bochten te wringen, terwijl de maker van de browser het gewoon moet fixen.
Dat is allemaal leuk en aardig, maar zolang de browserbouwer het niet fixed zul je er toch iets mee moeten. De klant komt namelijk bij jou zeuren.

De wereld ligt aan je voeten. Je moet alleen diep genoeg willen bukken...
"Wie geen fouten maakt maakt meestal niets!"


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22:10

.oisyn

Moderator Devschuur®

Demotivational Speaker

_Thanatos_ schreef op donderdag 05 juni 2008 @ 14:23:
[...]

Totdat de pagina uit het geheugen verdwijnt, en daarmee al het script van die pagina buiten scope raakt. Het nagenoeg enige dat nog in scope is, is window.name, maar die verdwijnt ook als het window/tab gesloten wordt. Dat is de theorie. Als de browser dit niet goed implementeert, dan is het flauwekul om je in allerlei rare bochten te wringen, terwijl de maker van de browser het gewoon moet fixen.
Leuk verhaal, in theorie. Totdat je webapplicatie een toch wat langere lifetime heeft, waardoor de pagina nooit buiten scope gaat omdat de gebruiker alles op dezelfde pagina kan doen, met als gevolg dat je alsnog weer beter na moet denken over object lifetime en het opruimen van je eigen zooi.

Dit nog even naast het valide punt van NetForce1: hoewel de oorzaak van de bug idd in de browser zit, kun jij niet van je gebruikers verlangen dat ze dan maar een één of andere denkbeeldige browser moeten gebruiken die wél alles goed doet, terwijl je er net zo makkelijk in je sourcecode omheen kunt werken en het sowieso good practice is om na te denken over verantwoordelijkheden en resource lifetime in je code, of je nou in een GC omgeving zit of niet. Wat javascript overigens sowieso niet per definitie is, want de EcmaScript specificatie rept geen woord over de memory requirements, dus het is niet eens een bug dat geheugen niet wordt opgeruimd.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 05-09 14:39

_Thanatos_

Ja, en kaal

de EcmaScript specificatie rept geen woord over de memory requirements, dus het is niet eens een bug dat geheugen niet wordt opgeruimd.
Dat is dan discutabel. In elk geval kent javascript alleen impliciete (en onoverzichtelijke, mag ik wel zeggen) manieren om geheugen op te ruimen. Als je moet vertrouwen om "bijverschijnselen" die ervoor zorgen dat geheugen opgeruimt wordt waar dat zonder truuks ook had moeten gebeuren, kun je je beter gaan richten op C++ ofzo: een taal waarin je wél je geheugen expliciet op dient te ruimen.

We kunnen trouwens ook massaal bij MS die browserlekken gaan melden. En bij Mozilla. Waarom niet. Het zijn tenslotte bugs. MS heeft daarvoor OneCare en Mozilla heeft Bugzilla. Opera heeft er zelfs een heel forum voor.

日本!🎌


  • Wolfboy
  • Registratie: Januari 2001
  • Niet online

Wolfboy

ubi dubium ibi libertas

Het punt is alleen dat het nogal lastig is om uit te vinden waar bepaalde problemen door komen, het onderzoeken wat een memory leak veroorzaakt kan best lastig zijn. Dus massaal melden is al een probleem, en daarnaast zegt het nog niets over het oplossen van de problemen, zolang de browser bouwers de gemeldde problemen niet oplossen lost het niets op.

Blog [Stackoverflow] [LinkedIn]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22:10

.oisyn

Moderator Devschuur®

Demotivational Speaker

_Thanatos_ schreef op donderdag 05 juni 2008 @ 19:35:
[...]

Dat is dan discutabel. In elk geval kent javascript alleen impliciete (en onoverzichtelijke, mag ik wel zeggen) manieren om geheugen op te ruimen.
En expliciete, zoals 'delete'.
Als je moet vertrouwen om "bijverschijnselen" die ervoor zorgen dat geheugen opgeruimt wordt waar dat zonder truuks ook had moeten gebeuren, kun je je beter gaan richten op C++ ofzo: een taal waarin je wél je geheugen expliciet op dient te ruimen.
Beetje ongelukkig voorbeeld: ook C++ zegt niets over het al dan niet beschikbaar zijn van een GC, en hoewel dat in de praktijk vaak niet zo is is er niets wat een implementatie tegenhoudt om wel een GC te implementeren ;)
We kunnen trouwens ook massaal bij MS die browserlekken gaan melden. En bij Mozilla. Waarom niet. Het zijn tenslotte bugs. MS heeft daarvoor OneCare en Mozilla heeft Bugzilla. Opera heeft er zelfs een heel forum voor.
Dat ze massaal gemeld worden betekent nog niet dat ze morgen ineens gefixed zijn. Of volgende week. 't Is dan ook niets dat je zomaar even repareert (het hele memory management model moet op de schop).

Bottom line is en blijft dat opletten wat je doet en wanneer je dingen 'vrijgeeft' belangrijk is, GC of niet. Dus ook in javascript.

[ Voor 5% gewijzigd door .oisyn op 06-06-2008 13:18 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Wolfboy
  • Registratie: Januari 2001
  • Niet online

Wolfboy

ubi dubium ibi libertas

Erkens schreef op woensdag 04 juni 2008 @ 23:28:
[...]

Nu begin ik aan mezelf te twijfelen...
Ik ga het morgen even testen/nazoeken als ik tijd heb :)
Als je nog even tijd hebt O-)

Ik ben persoonlijk erg benieuwd namelijk, of dit ook echt performance problemen geeft.

Blog [Stackoverflow] [LinkedIn]


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 23:43

crisp

Devver

Pixelated

Wolfboy schreef op vrijdag 06 juni 2008 @ 12:15:
[...]

Als je nog even tijd hebt O-)

Ik ben persoonlijk erg benieuwd namelijk, of dit ook echt performance problemen geeft.
Lijkt me niet, functiereferences zijn over het algemeen geen oorzaak van memory-leaks. In IE zijn het meestal referenties tussen DOM en JS objecten.

Intentionally left blank


  • Wolfboy
  • Registratie: Januari 2001
  • Niet online

Wolfboy

ubi dubium ibi libertas

Inderdaad Crisp, dat is het ook naar mijn weten.

HTML:
1
2
3
4
5
6
<script type="text/javascript">
function leak(){
  var leaking_element = document.createElement('<span onclick="leak_memory();">');
}
</script>
<span onclick="leak();">Add a leak</span>
Dit is naar mijn weten een memory leak in IE.

Blog [Stackoverflow] [LinkedIn]


  • BtM909
  • Registratie: Juni 2000
  • Niet online

BtM909

Watch out Guys...

Even een kick aangezien ik toevallig op dit artikel stuitte:

Finally, the alternative fix for IE6's memory leak is available

Doe ermee wat je wilt, sowieso handig voor onze kennisdatabase :P

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.

Pagina: 1