JavaScript memory leaks, czyli utracona pamięć


kamil avatar Kamil Wiśniewski 25 Czerwca 2017 1 3925 Share:
Wycieki pamięci w aplikacjach JavaScript - czym są, jak je diagnozować i jak się z nimi uporać?

Amnezja?

W pewnym sensie… Wycieki pamięci, to obszary pamięci, które zostały zaalokowane, ale w wyniku błędu programistycznego, nie mogą zostać zwolnione, mimo, że nie są już potrzebne. W JavaScript nie alokujemy pamięci bezpośrednio. Nie musimy też jawnie jej zwalniać, bo robi to za nas Garbage Collector. Skoro wszystko dzieje się automatycznie, to skąd biorą się błędy?

Przyczyny?

Najłatwiej chyba pokazać to poprzez przykłady. Poniżej kilka spośród tych najbardziej popularnych.

Przykład #1. Przypadkowa zmienna globalna

Spójrzmy na poniższy fragment kodu:

function memLeak() {
  a = new Array(9999);
}

W praktyce jest to odwołanie do niezadeklarowanej zmiennej. W JavaScript takie odwołanie skutkuje utworzeniem zmiennej globalnej, czyli niejawnie:

function memLeak() {
  window.a = new Array(9999);
}

W tym przypadku zapomnieliśmy o słowie kluczowym var:

function memLeak() {
  var a = new Array(9999);
}

Taka zmienna pozostanie w pamięci w całym zakresie globalnym aplikacji, zamiast zajmować ją tylko na czas wykonania funkcji.

Przykład #2. Zapomniany callback lub timer

var a = {
  text: "Hello world!"
};

setInterval(function(){
  var element = document.getElementById('element');
  element.innerHTML = a.text;
}, 5000);

W powyższym przykładzie kodu,nawet kiedy usuniemy element, nie zostanie on zebrany przez Garbage Collector, ponieważ nie pozwala na to wciąż działający interval. Dopóki działa interval, ze względu na odniesienie w nim zawarte, z pamięci nie zostanie również usunięty obiekt a. Kiedy usuwamy element, powinniśmy zawsze zatrzymać wszystkie timery i usunąć eventListener’y, które się do niego odnoszą.

Przykład #3. Zapomniane odwołanie do elementu DOM

Spójrzmy na poniższy przykład kodu:

var element1 = document.getElementById('el1');
var element2 = document.getElementById('el2');

element1.addEventListener("click", function(){
  element2.parentNode.removeChild(element2);
});

Element element2 nie zostanie usunięty z pamięci, bo odwołanie do niego wciąż jest zawarte w eventListener elementu element1.

var element = document.getElementById('element');

function memLeak() {
  document.body.removeChild(document.getElementById('element');
}

I znów podobna sytuacja. W tym przypadku mimo, że usunęliśmy element z drzewa DOM, referencja do niego wciąż istnieje, więc element pozostanie w pamięci.

Co dalej?

To tylko kilka najbardziej typowych i tym samym najbardziej oczywistych przykładów kodu, który może prowadzić do wycieków pamięci. Sposobów na gubienie pamięci może być jednak znacznie więcej i szczególnie przy bardziej rozbudowanych aplikacjach trudno się ich w 100% wystrzec. Na szczęście jednak istnieje wiele narzędzi, które mogą ułatwić diagnozowanie tego typu błędów i ich korygowanie.

W kolejnej części postaram się opisać w jaki sposób, za pomocą przeglądarkowych narzędzi developerskich sprawdzić czy w aplikacji istnieją wycieki pamięci i zlokalizować je w kodzie aplikacji.

Część 2: http://blog.insprit.pl/javascript-memory-leaks-czyli-utracona-pamiec-cz-2/

 

Komentarze

Nie ma jeszcze żadnych komentarzy. Skomentuj jako pierwszy!

Twój komentarzTwój adres email nie zostanie opublikowany

Nasza strona używa ciasteczek na wypadek gdybyś zgłodniał w trakcie jej przeglądania. Nie masz nic przeciwko? Pewnie, nie ma problemu!