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ć.