Memóriaszivárgás Internet Explorer böngészőben

A memóriában „felejtett„ referencia nélküli objektumokat memóriahézagoknak (memory leak) nevezzük. A memóriaszivárgás programhiba, mert az objektumok által lefoglalt memóriaterület nincsen felszabadítva, miután már nincsen rájuk szükség.

Web oldalak esetében memóriaszivárgásról akkor beszélhetünk biztosan, ha a böngészőbe olvasott web lapot egymás után többször újratöltjük, miközben a böngésző memóriaigénye növekszik. Amikor egy másik web lapot olvas be a böngésző, vagy ugyanazt a web lapot újratöltjük, az előzőleg beolvasott web lap által elfoglalt memóriának fel kellene szabadulnia. Ha ez nem történik meg, memóriaszivárgásról beszélünk. Böngészőnk memóriaigénye megnő, és a teljesítménye is lecsökkenhet. Ilyenkor az egyetlen megoldás a böngészőt becsukni, majd újraindítani.

function CreateDivs(){
    var oBigObject = new Array(1000).join(new Array(200).join("XXXXX"));
    for(var i = 0; i < 50; i++){
        var el = document.createElement('div');
        el.id = 'myDiv'+ i;
        el.className = 'box';
        el.onclick = function(){
            this.style.backgroundColor = 'red'; 
        }

        document.getElementsByTagName('body')[0].appendChild(el);
    }
};

window.onload = function(){
    CreateDivs();
}

A fenti kód memóriaszivárgást okoz Internet Explorer böngészőben. A fenti kódot tartalmazó web lapot Internet Explorer és Firefox böngészőkben próbáltam ki. A web lapot egymás után rövid időintervallumokban újratöltöttem, miközben monitoroztam a böngésző memóriafogyasztását. A memóriaszivárgás jól látható a memóriafoglalási grafikonon.

Az Internet Explorer memóriafogyasztása grafikonon

Az Internet Explorer memóriafogyasztása lépcsőzetesen nő, minden oldal frissítéssel. A lefoglalt memória akkor sem szabadult fel, miután egy teljesen üres web oldalat nyitottam meg a böngészőben.

A Firefox memóriafogyasztása grafikonon

A Firefox böngésző nem szivárogtatott memóriát, az allokált memóriát korrektül felszabadította.

Természetesen nemcsak Internet Explorernek vannak memóriaszivárgási gondjai. A leggyakrabban azonban mégis az Internet Explorer (főleg a 6-os és korábbi verziók) böngésző szokott memóriát szivárogtatni. Internet Explorer böngésző akkor szivárogtat memóriát, amikor körkörös hivatkozás jön létre egy JavaScript-objektum és egy befogadó környezet által nyújtott objektum (például DOM vagy ActiveX objektum) között. A továbbiakban a környezet által nyújtott objektumokat együttes néven csak COM-ként fogom említeni.

function leakMemory(){
    var elDiv = document.getElementById('myDiv');
    var jsObj = { 'div': elDiv };
    elDiv.expandoProperty = jsObj;
}

A fenti kód körkörös hivatkozás memória szivárgást okoz. Az Internet Explorer nem képes felszabadítani ez elDiv és jsObj által allokált memóriát, csak a böngésző bezárásakor szabadul fel a memória.

Körkörös hivatkozás egy DOM elem és egy JavaScript-objektum között.

Körkörös hivatkozás egy DOM elem és egy JavaScript-objektum között.

JavaScriptben DOM példányokat tetszőleges attribútumokkal bővíthetünk. Például: var oEl = document.getElementById('myDiv');
oEl.myprop = true;
Az így hozzáadott attribútumokat angolul expando property-nek nevezzük.

Annak ellenére, hogy JavaScript GC-je képes feloldani a körkörös hivatkozásokat, ebben az esetben ez mégsem történik meg. Ennek az az oka, hogy a körkörös hivatkozás JavaScript és COM (DOM) objektum között jött létre, és a COM-nak más GC-je van. A COM komponensek a hivatkozások számlálásával oldják meg az általuk használt erőforrások felszabadítását (reference-counting garbage collection). Az új hivatkozások megnövelik, a megszűnő referenciák pedig csökkentik egy számláló értékét. Ha a számláló értéke nulla, a komponensre már nincs szükség, és felszabadítja a hozzá tartozó memóriaterületet. A módszer gyenge pontja az, hogy a körkörös hivatkozásokat nem képes felismerni.

Az elDiv hivatkozásszámlálójának értéke mindaddíg 1-es marad, amíg a jsObj JavaScript-objektum nincs felszabadítva, de jsObj-re elDiv hivatkozik. A két objektum által elfoglalt memória sosem lesz felszabadítva.

A böngészők memóriaszivárgása nem újkeletű probléma, csak sokáig nem tartották érdemlegesnek foglalkozni a problémával. A JavaScript megjelenése idején figyelmeztető üzenetek és popupok feldobálásán kívül másra nemigen volt használható. Az utóbbi időben azonban felvirágzásnak indult a JavaScript. A mai modern webalkalmazások felhasználói felülete hihetetlenül látványos és felhasználóbarát, majdnem asztali alkalmazásokra jellemző interakcióval. Ezeknek a megalkotásához elkerülhetetlenné vált különböző JavaScript osztálykönyvtárak fejlesztése, amik sokszor bizony elérik akár a száz kilobájtos fájlméretet is. Ilyen temérdek JavaScript kód futtatásakor már érdemes odafigyelni a memóriaszivárgás elkerülésére, hiszen a memóriaszivárgás jelentős mértékű lehet, ami néha akár a böngésző lefagyásához is vezethet.