Jak naprawić „Błąd braku pamięci sterty JavaScript”

JavaScript, z uwagi na swoją wszechstronność, nadal plasuje się w czołówce najpopularniejszych języków programowania. Aby móc uruchamiać kod JavaScript poza przeglądarką internetową, programiści korzystają z Node.js, środowiska uruchomieniowego o charakterze wieloplatformowym.

Podczas pracy z projektami Node.js opartymi o JavaScript, częstym problemem jest występowanie błędu związanego z brakiem pamięci w stercie.

Ten błąd pojawia się, gdy zasoby pamięci operacyjnej, domyślnie przyznane przez system komputerowy, okazują się niewystarczające do sprawnego działania rozbudowanego projektu.

W przypadku natrafienia na błąd braku pamięci w stercie, aplikacja zostaje zatrzymana, a użytkownikowi wyświetlany jest jeden z komunikatów:

BŁĄD KRYTYCZNY: CALL_AND_RETRY_LAST Niepowodzenie alokacji – brak pamięci w stercie JavaScript

lub

Błąd krytyczny: Niepowodzenie alokacji nieprawidłowego rozmiaru tabeli – sterta JavaScript ma za mało pamięci

Źródła problemu braku pamięci w stercie JavaScript

  • Przetwarzanie rozległych struktur danych: operacje na dużych zbiorach danych, takich jak tablice czy macierze, angażują znaczne ilości pamięci, co może prowadzić do wyczerpania jej zasobów.

Poniżej przedstawiono przykład ilustrujący operację na dużej strukturze danych składającej się z miliarda elementów:

let array = [];

for (let i = 0; i < 1000000000; i++) {

  array.push(i);

}
  • Nieefektywne zarządzanie pamięcią: w procesie rozwoju aplikacji niezbędne jest zwalnianie obiektów, które nie są już potrzebne.

Oto przykład funkcji, która może skutkować wyciekiem pamięci:

let array = [];

setInterval(function() {

  array.push(new Array(1000000).join("x"));

}, 1000);
  • Niekończące się pętle: kod, w którym warunek zakończenia pętli nigdy nie jest spełniony, będzie działał w nieskończoność.

Poniżej prezentujemy przykład nieskończonej pętli:

while (true) {

    console.log(1);

}

Tego typu pętle mogą wywołać omawiany błąd poprzez szybkie wyczerpywanie dostępnej pamięci.

  • Funkcje rekurencyjne: funkcja rekurencyjna to taka, która wywołuje samą siebie – bezpośrednio lub pośrednio – w celu powtarzania danego zestawu instrukcji, aż do spełnienia warunków zakończenia. Jeżeli mechanizm rekurencji nie jest właściwie zaimplementowany, może prowadzić do nadmiernego zużycia pamięci, a w konsekwencji – do błędu przepełnienia sterty.
  • Duża liczba obiektów w kodzie: gdy w programie występuje wiele dużych obiektów, łączna ilość pamięci przez nie zajmowana może przekroczyć dostępny limit.

Rozwiązywanie problemu braku pamięci w stercie JavaScript

Błąd ten może pojawić się niezależnie od systemu operacyjnego: Windows, macOS czy Linux (w tym Ubuntu). Na szczęście istnieją sposoby na jego naprawienie w każdym z tych środowisk.

#1. Usuwanie błędu braku pamięci sterty JavaScript w systemie Windows

Krok 1: Otwórz menu Start i wyszukaj „Zaawansowane ustawienia systemu”.

Krok 2: W lewym dolnym rogu okna kliknij „Zmienne środowiskowe”.

Krok 3: Wybierz „Nowy” w sekcji „Zmienne użytkownika” lub „Zmienne systemowe”. Pierwsza opcja spowoduje wprowadzenie zmian tylko dla bieżącego konta użytkownika, natomiast druga – dla całego systemu.

Krok 4: W oknie dialogowym, które się pojawi, w polu „Nazwa zmiennej” wpisz NODE_OPTIONS, a w polu „Wartość zmiennej” –max-old-space-size=4096. W tym przypadku 4096 oznacza 4 GB pamięci wirtualnej przydzielonej dla Node.js. Możesz zwiększyć tę wartość, na przykład do 8 GB, wpisując –max-old-space-size=8192.

Krok 5: Kliknij „OK”, „Zastosuj”, a następnie ponownie „OK”, aby zatwierdzić zmiany.

Możesz także posłużyć się terminalem Windows PowerShell, aby rozwiązać problem. Otwórz terminal i wprowadź następujące polecenie:

env:NODE_OPTIONS="--max-old-space-size=4096"

Możesz także tymczasowo rozwiązać problem, uruchamiając to polecenie przed uruchomieniem aplikacji:

set NODE_OPTIONS=--max-old-space-size=4096

#2. Usuwanie błędu braku pamięci sterty JavaScript w systemie Linux

  • Krok 1: Zlokalizuj źródło błędu, analizując logi konsoli lub komunikaty wyjściowe, aby zidentyfikować problematyczne linie kodu.
  • Krok 2: Wyeksportuj zmienną środowiskową, określając wielkość pamięci wirtualnej przydzielonej dla Node.js. Użyj w tym celu polecenia:
export NODE_OPTIONS=--max-old-space-size=4096

Powyższe kroki przydzielą 4 GB pamięci wirtualnej dla Node.js. Jeżeli problem nadal będzie występował, możesz spróbować podwoić tę wartość.

Na przykład, aby przydzielić 8 GB pamięci wirtualnej, wprowadź polecenie:

export NODE_OPTIONS=--max-old-space-size=8192

#3. Usuwanie błędu braku pamięci sterty JavaScript w systemie macOS

W systemie macOS możesz rozwiązać problem braku pamięci w stercie JavaScript, stosując podobne podejście jak w systemie Linux. Wykonaj następujące kroki:

  • Krok 1: Zidentyfikuj źródło błędu, sprawdzając logi konsoli lub dane wyjściowe, aby wskazać przyczynę problemu w kodzie.
  • Krok 2: Wyeksportuj zmienną środowiskową, która określa rozmiar pamięci wirtualnej alokowanej dla Node.js. Użyj następującego polecenia:
export NODE_OPTIONS=--max-old-space-size=4096

Powyższe kroki przydzielą 4 GB pamięci wirtualnej dla Node.js. Jeśli błąd nadal będzie się pojawiał, możesz zwiększyć przydział pamięci.

Na przykład, aby przydzielić 8 GB pamięci wirtualnej, użyj polecenia:

export NODE_OPTIONS=--max-old-space-size=8192

Zwiększanie pamięci podczas instalacji NPM

Dotychczas przedstawione rozwiązania dotyczą sytuacji, gdy błąd pojawia się w trakcie uruchamiania aplikacji Node.js. Możliwe jest jednak przydzielenie większej ilości pamięci wirtualnej także w celu rozwiązania problemów z brakiem pamięci podczas instalacji pakietów JavaScript. W tym celu należy skorzystać z polecenia:

node --max-old-space-size=4096 (which npm) install

Uwaga: możesz stopniowo zwiększać alokację pamięci wirtualnej – o 1 GB, 2 GB, 3 GB lub 4 GB. Rozmiar pamięci musi być podany w MB. Nie zaleca się jednak przydzielania całej dostępnej pamięci maszyny na potrzeby Node.js, ponieważ może to spowodować awarię. Dobrą praktyką jest przydzielenie Node.js nie więcej niż połowy dostępnej pamięci RAM; na przykład, jeżeli masz 16 GB RAM, możesz przydzielić do 8 GB.

Zapobieganie błędom przepełnienia sterty JavaScript

Wcześniej omówiliśmy, jak naprawić błąd braku pamięci sterty JavaScript. Na szczęście istnieją także metody, które pozwalają uniknąć wystąpienia tego błędu. Oto kilka rekomendowanych praktyk:

#1. Przetwarzanie danych w mniejszych partiach

Załóżmy, że masz aplikację Node.js, która importuje duże zbiory danych z plików CSV w ramach procesu ETL (Extract – Transform – Load). Twoja aplikacja może ulegać awarii podczas próby importu. Jeśli pracujesz z MongoDB, możesz podzielić pliki na mniejsze części, korzystając z instrukcji wiersza poleceń, takiej jak:

split -l 1000000 users.csv

Powyższe polecenie instruuje Node.js, aby podzielił plik users.csv na wiele plików, z których każdy będzie zawierał 1 000 000 wierszy (użytkowników). Flaga -l wskazuje, że podział pliku powinien być dokonywany na podstawie liczby wierszy.

#2. Monitorowanie zużycia pamięci

Możesz posłużyć się profilerem pamięci, aby identyfikować wycieki pamięci w kodzie. W tym celu możesz skorzystać z wbudowanych narzędzi Node.js oraz ChromeDevTools. Oba te rozwiązania pomogą Ci wykryć i usunąć potencjalne problemy.

Możesz też wykorzystać narzędzia firm trzecich, takie jak Datadog, New Relic i AppDynamics, które umożliwiają monitorowanie wydajności aplikacji. Dodatkowo, informacje o zużyciu pamięci przez aplikację Node.js możesz uzyskać za pomocą metody process.memoryUsage().

#3. Unikanie wycieków pamięci

Wycieki pamięci mają miejsce, gdy aplikacja Node.js przechowuje odwołania do obiektów, które nie są już jej potrzebne. Jeżeli te nieużywane obiekty nie zostaną usunięte, z upływem czasu zużycie pamięci będzie narastać.

Istnieje kilka sposobów zapobiegania wyciekom pamięci, takich jak unikanie zmiennych globalnych w kodzie, unikanie blokowania operacji wejścia-wyjścia, a także korzystanie ze słów kluczowych let i const zamiast var podczas deklarowania zmiennych.

#4. Wykorzystywanie procesów potomnych

Jeżeli używasz Node.js na urządzeniu z ograniczoną ilością pamięci (np. Raspberry Pi), istnieje ryzyko częstego występowania błędu braku pamięci w stercie. W takiej sytuacji warto zastosować architekturę z procesem głównym i procesami potomnymi. Gdy proces nadrzędny stwierdzi, że systemowi zaczyna brakować pamięci, będzie mógł zakończyć jeden z obciążonych procesów potomnych, a zadanie przydzielić innemu procesowi.

#5. Uaktualnienie sprzętu

Jeżeli zwiększenie alokacji pamięci i wprowadzenie powyższych metod zapobiegania nie rozwiązują problemu, warto rozważyć modernizację sprzętu. Node.js może działać nawet na maszynach z 512 MB pamięci RAM, ale Twoja aplikacja, w miarę rozwoju, będzie wymagała więcej zasobów.

Również zwiększenie liczby procesorów może korzystnie wpłynąć na alokację pamięci. Dwa lub więcej rdzeni pozwolą aplikacji na wykorzystanie wątków roboczych w zadaniach intensywnie korzystających z procesora, takich jak kryptografia czy przetwarzanie obrazów.

Najczęściej zadawane pytania

Jakie są przyczyny błędu braku pamięci w stercie JavaScript?

Ten błąd może wynikać z kilku przyczyn:
1. Wycieki pamięci
2. Nieskończone pętle
3. Duża liczba obiektów w projekcie
4. Przetwarzanie obszernych struktur danych

Czy błąd braku pamięci sterty JavaScript można naprawić?

Tak. Możesz rozwiązać ten problem, stosując następujące metody:
1. Przydzielenie większej ilości pamięci wirtualnej dla Node.js
2. Eliminowanie wycieków pamięci
3. Optymalizowanie kodu
4. Ulepszenie sprzętu

Jak rozwiązać problem braku pamięci w stercie w aplikacji React?

React jest popularną biblioteką JavaScript. W katalogu głównym projektu znajdź plik package.json i zmodyfikuj sekcję „scripts” w następujący sposób:

"scripts": {

    "start": "react-scripts --max_old_space_size=4096 start",

    "build": "react-scripts --max_old_space_size=4096 build",

    "test": "react-scripts test",

    "eject": "react-scripts eject"

}

Podsumowanie

Większość programistów jest przyzwyczajona do debugowania błędów w kodzie, a nie do problemów z pamięcią w czasie wykonywania programów Node.js. Na szczęście nie jest to sytuacja bez wyjścia, gdyż błąd braku pamięci sterty da się naprawić. W tym artykule omówiliśmy, czym jest ten błąd, jak go rozwiązać i jak zapobiegać jego wystąpieniu w przyszłych projektach Node.js.

Zachęcamy także do zapoznania się z artykułem na temat unikania typowych błędów w JavaScript.


newsblog.pl