Cum să remediați „Eroarea de memorie JavaScript Heap Out of Memory”

JavaScript se menține ca unul dintre cele mai populare limbaje de programare, datorită adaptabilității sale remarcabile. Pentru a executa cod JavaScript în afara unui mediu de browser, dezvoltatorii folosesc Node.js, un mediu de rulare ce funcționează pe multiple platforme.

Eroarea de epuizare a memoriei în JavaScript este o problemă frecvent întâlnită la rularea proiectelor Node.js.

Această eroare apare atunci când memoria alocată de sistemul informatic nu este suficientă pentru a suporta un proiect de dimensiuni mari.

În cazul în care vă confruntați cu această eroare, programul se va opri brusc, afișând unul dintre următoarele mesaje:

EROARE FATALĂ: CALL_AND_RETRY_LAST Alocarea nu a reușit – memorie JavaScript epuizată

Sau

Eroare fatală: alocarea nevalidă a dimensiunii tabelului a eșuat – memorie javascript epuizată

Cauzele care duc la eroarea de epuizare a memoriei în JavaScript

  • Utilizarea structurilor de date voluminoase: Prelucrarea structurilor mari, cum ar fi vectorii sau matricile, consumă o cantitate semnificativă de memorie, putând provoca această eroare.

Exemplu de structură de date mare, cu un miliard de elemente:

let array = [];
for (let i = 0; i < 1000000000; i++) {
    array.push(i);
}
  • Management deficitar al memoriei: Pe măsură ce o aplicație se dezvoltă, este esențial să eliberați din memorie obiectele care nu mai sunt necesare.

Exemplu de funcție care provoacă pierderi de memorie:

let array = [];
setInterval(function() {
    array.push(new Array(1000000).join("x"));
}, 1000);
  • Bucle infinite: Un astfel de cod se execută continuu, deoarece condiția de oprire nu este niciodată îndeplinită.

Exemplu de buclă infinită:

while (true) {
    console.log(1);
}

Buclele infinite consumă rapid memoria, conducând la această eroare.

  • Funcții recursive: O funcție recursivă se autoapelează pentru a repeta un set de instrucțiuni până când se îndeplinește o condiție. Dacă nu sunt corect gestionate, pot cauza scurgeri de memorie și, în final, această eroare.
  • Prezența unui număr mare de obiecte: Dacă un cod conține multe obiecte mari, memoria utilizată de acestea în mod colectiv poate depăși limita alocată.

Cum remediem eroarea de epuizare a memoriei în JS

Această eroare poate apărea pe Windows, macOS și Linux, inclusiv Ubuntu. Din fericire, poate fi corectată indiferent de sistemul de operare.

#1. Remedierea erorii pe Windows

Pasul 1: Accesați meniul Start și căutați „Setări avansate de sistem”.

Pasul 2: În dialogul apărut, selectați „Variabile de mediu”.

Pasul 3: Apăsați „Nou” fie în secțiunea „Variabile utilizator”, fie în „Variabile sistem”. Prima opțiune afectează doar utilizatorul curent, a doua, întregul sistem.

Pasul 4: În fereastra nouă, introduceți „NODE_OPTIONS” la „Nume variabilă” și „–max-old-space-size=4096” la „Valoare variabilă”. Valoarea „4096” alocă 4GB de memorie virtuală pentru Node.js. Puteți aloca mai mult, de exemplu 8GB, folosind „–max-old-space-size=8192”.

Pasul 5: Confirmați modificările apăsând „OK”, „Aplicați” și din nou „OK”.

Alternativ, puteți folosi terminalul Windows PowerShell. Deschideți-l și introduceți:

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

Pentru o soluție temporară, puteți executa următoarea comandă înainte de a rula aplicația:

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

#2. Remedierea erorii pe Linux

  • Pasul 1: Identificați sursa erorii. Consultați jurnalele sau consola pentru a determina linia de cod sau fișierul problematic.
  • Pasul 2: Exportați variabila de mediu ce specifică memoria virtuală alocată Node.js, folosind comanda:
export NODE_OPTIONS=--max-old-space-size=4096

Acești pași alocă 4GB de memorie virtuală. Dacă eroarea persistă, măriți dimensiunea alocată. De exemplu, pentru 8GB:

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

#3. Remedierea erorii pe macOS

Soluția pentru macOS este similară cu cea pentru Linux. Urmați acești pași:

  • Pasul 1: Identificați sursa erorii din jurnale sau consolă.
  • Pasul 2: Exportați variabila de mediu pentru a specifica alocarea de memorie Node.js:
export NODE_OPTIONS=--max-old-space-size=4096

Acești pași alocă 4GB de memorie virtuală. Dacă eroarea persistă, creșteți alocarea. De exemplu, pentru 8GB:

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

Creșterea memoriei în timpul instalării NPM

Soluțiile prezentate până acum se referă la erorile ce apar în timpul rulării unei aplicații Node.js. Totuși, puteți aloca memorie virtuală și în timpul instalării pachetelor JavaScript, folosind această comandă:

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

Notă: Puteți crește alocarea memoriei cu 1GB, 2GB, 3GB sau 4GB. Dimensiunea memoriei trebuie specificată în MB. Evitați alocarea întregii memorii, deoarece poate duce la blocarea programului. Ca recomandare, dacă aveți 16GB, alocați maximum 8GB pentru Node.js.

Cum prevenim eroarea de epuizare a memoriei în JavaScript

Pe lângă remedierea acestei erori, este important să luăm măsuri preventive pentru a evita apariția ei în viitoarele proiecte. Iată câteva abordări eficiente:

#1. Împărțiți datele în bucăți mai mici

Dacă aplicația Node.js importă seturi mari de date din fișiere CSV, de exemplu prin procesul ETL (Extragere-Transformare-Încărcare), este posibil ca ea să se blocheze. Dacă folosiți MongoDB, puteți împărți fișierul în bucăți mai mici, folosind comanda:

split -l 1000000 users.csv

Această comandă împarte fișierul „users.csv” în fișiere mai mici, fiecare conținând 1.000.000 de linii. Indicatorul „-l” specifică faptul că împărțirea se face pe baza numărului de linii.

#2. Monitorizați utilizarea memoriei

Utilizați un profiler de memorie pentru a depista scurgerile de memorie. Puteți folosi memoria încorporată a Node.js și ChromeDevTools. Aceste instrumente pot detecta problemele din cod. Puteți folosi instrumente externe, precum Datadog, New Relic și AppDynamics, pentru a monitoriza performanța aplicației și a lua măsuri. De asemenea, folosiți `process.memoryUsage()` pentru a verifica utilizarea memoriei în aplicația Node.js.

#3. Evitați scurgerile de memorie

Scurgerile de memorie apar atunci când aplicația Node.js reține referințe către obiecte care nu mai sunt necesare. Aceste obiecte, nefiind eliminate, duc la acumularea de memorie. Pentru a evita scurgerile, evitați variabilele globale, blocați operațiunile I/O și folosiți „let” și „const” în loc de „var” la declararea variabilelor.

#4. Folosiți procese secundare

Dacă rulați Node.js pe o mașină cu memorie limitată, cum ar fi Raspberry Pi, este posibil să vă confruntați mai des cu această eroare. Folosiți un proces principal și altele secundare. Când procesul principal detectează că memoria este insuficientă, oprește procesul problematic și alocă sarcina unuia mai puțin încărcat.

#5. Actualizați hardware-ul

Dacă creșterea memoriei alocate și măsurile preventive nu rezolvă problema, luați în considerare actualizarea hardware-ului. Node.js poate rula cu 512 MB de RAM, dar va necesita mai multă memorie pe măsură ce aplicația se dezvoltă. De asemenea, un număr mai mare de procesoare îmbunătățește alocarea memoriei. Două sau mai multe procesoare permit aplicației să folosească fire de execuție pentru sarcini CPU-intensive, cum ar fi criptografia sau procesarea imaginilor.

Întrebări frecvente

Ce cauzează eroarea de epuizare a memoriei în JavaScript?

Eroarea poate fi cauzată de mai mulți factori:
1. Scurgeri de memorie
2. Bucle infinite
3. Număr mare de obiecte în proiect
4. Structuri de date mari

Poate fi rezolvată eroarea de epuizare a memoriei în JavaScript?

Da. Puteți rezolva eroarea prin:
1. Alocarea mai multă memorie virtuală
2. Eliminarea scurgerilor de memorie
3. Optimizarea codului
4. Actualizarea hardware-ului

Cum remediați eroarea într-o aplicație React?

React este o bibliotecă JavaScript foarte populară. Adăugați următoarele linii în secțiunea de scripturi din `package.json`:

"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"
}

Încheiere

Majoritatea dezvoltatorilor se confruntă cu erori de codare, nu cu erori de rulare. Din fericire, eroarea de epuizare a memoriei este remediabilă. Am definit această eroare, am explicat cum o putem corecta și cum o putem evita în proiectele Node.js viitoare.

În continuare, puteți citi și despre cum să evitați alte erori comune în JavaScript.