Node.js - Allocation failed - Javascript out of memory?
Problem z limitem pamięci w Node.js to bardzo częsta przypadłość, kiedy pracujemy przy dużych projektach frontend.
Jeżeli podczas budowania produkcyjnej wersji aplikacji lub serwowania wersji deweloperskiej zobaczysz w swojej konsoli <--- Last few GCs --->
i Allocation failed - javascript heap out of memory
to bardzo wyraźna informacja dla Ciebie, że system nie przeznacza wystarczającej ilości pamięci dla Node.js.
Domyślny limit przeważnie jest mniejszy niż 2GB. Jak sobie poradzić z tym problemem? Przeczytaj ten szybki tip.
Po czym poznać, że problemem jest brak pamięci?
<--- Last few GCs --->
[13578:0x2a139e0] 307054 ms: Mark-sweep 1329.3 (1438.2) -> 1329.6 (1437.7) MB, 525.4 / 0.0 ms (average mu = 0.539, current mu = 0.058) allocation failure scavenge might not succeed
[13578:0x2a139e0] 308180 ms: Mark-sweep 1330.2 (1437.7) -> 1330.0 (1456.7) MB, 1123.4 / 0.0 ms (average mu = 0.268, current mu = 0.001) allocation failure scavenge might not succeed
<--- JS stacktrace --->
...
..
.
Aborted (core dumped)
Powyższy listing to przykład tego jak Node informuje o braku pamięci, przeważnie w powyższym zrzucie pamięci można wyczytać komunikat allocation failure
.
Rozwiązanie problemu z brakiem pamięci
Parametr max-old-space-size
Korzystając z polecenia node bezpośrednio, np. w przypadku uruchamiania prostych skryptów Node.js, możemy podczas uruchamiania polecenia dodać parametr max-old-space-size
, który bezpośrednio przekaże do Node konkretną wartość megabajtów, które chcesz przeznaczyć na procesy Node.js:
node --max-old-space-size=2048 index.js # limit zwiększony do 2gb
node --max-old-space-size=3072 index.js # limit zwiększony do 3gb
node --max-old-space-size=4096 index.js # limit zwiększony do 4gb
node --max-old-space-size=5120 index.js # limit zwiększony do 5gb
node --max-old-space-size=6144 index.js # limit zwiększony do 6gb
node --max-old-space-size=7168 index.js # limit zwiększony do 7gb
node --max-old-space-size=8192 index.js # limit zwiększony do 8gb
Czasami jednak nie jest to tak proste, np. podczas uruchamiania aplikacji Angular wykorzystując do tego Angular-CLI nie wywołujemy node
bezpośrednio:
ng serve myapp
w powyższym przykładzie przekazanie parametru max-old-space-size nic nie da.
Rozwiązanie dla starszych wersji Node.js
W wielu swoich projektach, które wykorzystują trochę starsze wersje Node(v5, v6, v7) wykorzystuję dodatkową bibliotekę increase-memory-limit
, którą możesz wyszukać na stronie npmjs.com.
Dzięki niej w prosty sposób możesz zmodyfikować wszystkie swoje zależności w katalogu node_modules
. Skrypt increase-memory-limit
automatycznie wyszukuje wywołania node
w skryptach i dodaje do nich parametr o którym wspomniałem wcześniej. Wygodny sposób na szybkie zwiększenie limitów, niestety ma też swoje wady.
Używając tej biblioteki musisz pamiętać, że po każdym usunięciu katalogu z zależnościami NPM musisz ponownie wykonać polecenie, sprawa dodatkowo komplikuje się na serwerze do budowania wersji testowych i produkcyjnych, gdzie przeważnie pobierasz kod źródłowy z repozytorium za każdym razem na nowo i ponownie instalujesz wszystkie zależności projektu
Rozwiązanie dla Node 8
Na szczęście w nowszych wersjach Node.js(od wersji 8 wydanej w sierpniu 2017 roku) możemy zwiększyć limit pamięci za pomocą zmiennej środowiskowej. Wystarczy dodać do systemu Linux:
export NODE_OPTIONS=--max_old_space_size=8192
żeby zwiększyć limit pamieci do 8GB.
W systemach Windows wygląda to analogicznie:
set NODE_OPTIONS=--max_old_space_size=8192
Musisz pamiętać, że polecenia export
i set
działają na czas sesji terminala, dlatego warto dodać zmienną do systemu na stałe.
Podsumowanie
Prędzej, czy później każdego programistę używającego Node.js powyższy problem będzie dotyczył, mam nadzieję że jasno i przejrzyście wyjaśniłem w czym jest problem oraz jak go szybko rozwiązać.