Mundarija (28)
- Bu darsda
- 1. Nega bu kerak?
- 2. Heap ichida nima bor
- 2.1 Stack va heap — qisqa eslatma
- 2.2 Avlodlar: young va old
- 2.3 Node 24 dagi bo'limlar ro'yxati
- 3. Heap limiti: qancha va nega
- 3.1 O'lchov: sukut va bayroqlar
- 3.2 Natijani o'qiymiz
- 3.3 Foiz bilan: --max-old-space-size-percentage
- 3.4 Bayroqni berish yo'llari
- 4. Chegaraga yetganda
- 4.1 Tajriba: 64 MB va cheksiz massiv
- 4.2 Oldini olish
- 5. process.memoryUsage() ni o'qish
- 5.1 Besh maydon
- 5.2 Bir million obyekt qancha joy oladi
- 5.3 Buffer heap'dan tashqarida
- 6. --trace-gc — GC'ni ko'z bilan ko'rish
- 7. CLI qadami: holat yo'q
- 8. Ko'p uchraydigan xatolar
- 9. Mashqlar
- 1-mashq (oson): qaysi maydon?
- 2-mashq (o'rta): limitni oldindan hisoblang
- 3-mashq (qiyin): xotira hisoboti
- 10. Real ishda
- Xulosa
- Manbalar
Node.js xotira limitlari: --max-old-space-size va heap statistikasi
Qisqacha: Node'dagi har JS obyekt V8 heap'ida yashaydi va heap'ning chegarasi bor. 16 GB RAM'li kompyuterda Node 24 sukut bo'yicha ~4,2 GB beradi. O'lchandi: 4 288 MB.
--max-old-space-size=256uni o'zgartiradi — lekin natija 256 emas, 448 MB: unga young generation uchun 192 MB qo'shiladi (o'lchandi). Chegaraga yetgandaFATAL ERROR: … JavaScript heap out of memorybilan jarayon o'ladi, exit kod 134 —try/catchbuni ushlamaydi. Kuzatish uchun:process.memoryUsage()(rss, heapUsed, external) vav8.getHeapStatistics().Bufferma'lumoti heap'dan tashqarida — uning hajmi bu limitga kirmaydi.
Bu darsda
- Heap qanday bo'limlarga bo'linishini (young, old, large object) va GC ularni qanday tozalashini bilasiz.
- Sukut heap limiti qanday hisoblanishini va
--max-old-space-sizeaslida nimani o'zgartirishini o'lchov bilan tushuntira olasiz. process.memoryUsage()dagirss,heapTotal,heapUsed,external,arrayBuffersni o'qiy olasiz.- "heap out of memory" xatosini taniysiz va uni qanday oldini olishni bilasiz.
--trace-gcchiqishidan Scavenge va Mark-Compact ni ajratasiz.
Oldin bilishingiz kerak: Xotira boshqaruvi va garbage collection, Hidden classes va inline caching, process obyekti.
1. Nega bu kerak?
Kichik VPS — 1 GB RAM. Unda Node server va ma'lumotlar bazasi ishlaydi. Bir kuni server hisobot yasash paytida yiqildi, logda:
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memoryTarjimasi: "Heap chegarasiga yetildi, joy ajratib bo'lmadi — JavaScript heap'ida xotira tugadi". Ikki savol tug'iladi. Birinchisi: chegara qancha edi va uni kim qo'ygan? Ikkinchisi: try/catch nega ushlamadi?
Teskari holat ham bo'ladi. 32 GB'li serverda dastur 3 GB dan oshganda yiqiladi, garchi 25 GB bo'sh tursa ham. Sababi bir xil — V8 heap chegarasi kompyuterning RAM'iga teng emas.
Xotira boshqaruvi va GC darsida g'oyani ko'rgansiz: obyektlar heap'da, unga yetib boradigan havola qolmasa — GC tozalaydi. Bu dars Node'ning amaliy tomoni: chegara qancha, uni qanday o'zgartirish va o'lchash.
O'xshatish: omborxona. Do'kon egasi (V8) omborga chegara qo'ygan — "ko'pi bilan 4 ta xona". Tovar ko'paysa, omborchi (GC) eski, kerakmas qutilarni chiqarib tashlaydi. Lekin hamma quti kerakli bo'lsa va 5-xona kerak bo'lsa — ish to'xtaydi, binoda bo'sh xona bo'lsa ham.
2. Heap ichida nima bor
2.1 Stack va heap — qisqa eslatma
J-173 darsidan: stack (stek) — funksiya chaqiruvlari va kichik oddiy qiymatlar, avtomatik tozalanadi. Heap (uyum) — obyektlar, massivlar, satrlar, funksiyalar; ularni GC tozalaydi. Stack ham cheklangan — juda chuqur rekursiya uni to'ldiradi:
let depth = 0;
function dive() {
depth++;
dive();
}
try {
dive();
} catch (e) {
console.log(`${e.name}: ${e.message}`, depth);
}Biz ishga tushirdik (Node 24.21.0, Windows):
RangeError: Maximum call stack size exceeded 12487Stack to'lishi — oddiy RangeError, uni try/catch ushlaydi. Heap to'lishi esa boshqacha — pastda ko'rasiz.
2.2 Avlodlar: young va old
V8 obyektlarni "yoshi" bo'yicha ikki avlodga ajratadi. Bu g'oya generational GC (avlodli yig'ish) deyiladi va bitta kuzatuvga asoslanadi: obyektlarning ko'pchiligi tez o'ladi. Funksiya ichidagi vaqtinchalik massiv, map natijasi, satr birlashtirish — millisekundlarda keraksiz bo'ladi.
| Bo'lim | Nima | Qanday tozalanadi |
|---|---|---|
Young generation (new_space) |
yangi obyektlar; kichik (o'nlab MB) | Scavenge — tez, tez-tez |
Old generation (old_space) |
ikki Scavenge'dan omon qolganlar | Mark-Sweep-Compact — sekinroq, kamroq |
| Large object space | katta obyektlar (masalan uzun massiv) | old bilan birga |
| Code space | JIT kompilyatsiya qilingan kod | — |
Diagrammada obyekt hayotini kuzating:
flowchart LR
N["yangi obyekt"] --> Y["young generation<br/>(semi-space)"]
Y -->|"Scavenge: o'lik"| X["tozalandi"]
Y -->|"2 marta omon qoldi"| O["old generation"]
O -->|"Mark-Sweep-Compact"| XScavenge — young generation'ni tozalash. Young ikki teng yarimga (semi-space) bo'lingan. Tirik obyektlar bir yarimdan ikkinchisiga ko'chiriladi, qolgani butunlay tashlanadi. Ish faqat tiriklar soniga bog'liq — o'liklar ko'p bo'lsa ham tez.
Mark-Sweep-Compact — old generation uchun uch qadam: tirik obyektlarni belgilash (mark), o'liklarni bo'shatish (sweep), bo'laklarni bir joyga zichlash (compact). Bu og'irroq, ba'zi qismlari JS'ni to'xtatadi — "GC pauzasi".
2.3 Node 24 dagi bo'limlar ro'yxati
v8.getHeapSpaceStatistics() har bo'lim haqida ma'lumot beradi. Nomlari V8 versiyasiga bog'liq — bu blok Node 24 (V8 13.6) da tekshirilgan:
import v8 from "node:v8";
const names = v8.getHeapSpaceStatistics().map((s) => s.space_name);
console.log(names.length);
console.log(names.slice(0, 4).join(", "));Konsolda:
13
read_only_space, new_space, old_space, code_space13 ta bo'lim: yuqoridagi jadvaldagilar va V8'ning ichki xavfsizlik va ulashilgan bo'limlari (trusted_space, shared_space …). Kundalik ishda new_space, old_space va large_object_space yetarli.
Tekshirib ko'ring: Server har so'rovda 50 KB lik vaqtinchalik obyekt yaratadi va javobdan keyin uni unutadi. Bu obyektlar qaysi bo'limda o'ladi va qaysi GC ularni tozalaydi?
Javob
Young generation'da, Scavenge bilan. Ular ikki Scavenge'dan omon qolmaydi — old generation'ga yetib bormaydi. Generational GC aynan shunday "tez o'ladigan" obyektlar uchun qurilgan, shuning uchun bunday ish arzon.
3. Heap limiti: qancha va nega
3.1 O'lchov: sukut va bayroqlar
Heap chegarasini v8.getHeapStatistics().heap_size_limit ko'rsatadi. Kanon tajribasi (16 GB RAM, Node 24.21.0) va bizning qo'shimcha o'lchovimiz:
node -p "require('v8').getHeapStatistics().heap_size_limit / 2**20"
node --max-old-space-size=256 -p "..." # xuddi shu ifoda| Bayroq | heap_size_limit |
|---|---|
| (sukut) | 4 288 MB |
--max-old-space-size=256 |
448 MB |
--max-old-space-size=8192 |
8 384 MB |
--max-semi-space-size=16 |
4 144 MB |
--max-old-space-size=256 --max-semi-space-size=16 |
304 MB |
--max-old-space-size-percentage=10 |
1 797 MB |
Grafikda ko'ring — qaysi bayroq qanchalik ta'sir qiladi:
- sukut4 288 MB
- old=256256 + 192448 MB
- old=256, semi=16256 + 48304 MB
- old 10%1 605 + 1921 797 MB
- old=81928 192 + 1928 384 MB
Manba: O'lchandi: IlmHamroh kanoni (sukut, 256, 8192) va yozuvchi (semi, percentage); Node 24.21.0, Windows 11, 16 GB RAM, 2026-10-23
3.2 Natijani o'qiymiz
Ikki qonuniyat ko'rinadi.
Birinchisi: "old" faqat bir qismi. --max-old-space-size — nomidan ko'rinib turganidek, faqat old generation chegarasi. Umumiy limitga young generation ham qo'shiladi. Har o'lchovda farq bir xil — 192 MB. --max-semi-space-size=16 bilan esa farq 48 MB bo'ldi: 192 = 3 × 64, 48 = 3 × 16. Ya'ni young uchun semi-space hajmining uch baravari ajratiladi (ikki semi-space va katta yangi obyektlar uchun joy — bu V8 ichki hisobi, hujjatda tafsiloti yo'q; biz faqat o'lchovdan xulosa qildik).
Amaliy saboq: konteynerga 512 MB berib, Node'ga --max-old-space-size=512 yozsangiz, heap 704 MB gacha o'sishi mumkin. Unga kod, stack va Buffer ham qo'shiladi. OS jarayonni xotira tugadi deb o'ldiradi. Qoida: old-space chegarasini ajratilgan xotiradan ancha kam qo'ying (odatda 70–75 foiz atrofida — bu jamoalar orasidagi amaliy maslahat, qat'iy qoida emas).
Ikkinchisi: sukut RAM'ga bog'liq. 16 GB'da sukut old-space 4 096 MB (4 288 − 192). V8 old-space chegarasini fizik xotiradan hisoblaydi va 64-bitli tizimlarda yuqori chegara qo'yadi. Shuning uchun 32 GB'li serverda ham sukut taxminan shunday qoladi — katta ma'lumot bilan ishlaydigan dasturga bayroq kerak. Kichik xotirali mashinada esa sukut kamroq. Aniq formula V8 versiyasiga bog'liq va hujjatlashtirilmagan — har mashinada o'lchang.
3.3 Foiz bilan: --max-old-space-size-percentage
Node 24 ning yangi versiyalarida foiz bilan berish mumkin: --max-old-space-size-percentage=10 — "fizik xotiraning 10 foizi". O'lchovda: 16 052 MB × 0,10 ≈ 1 605 + 192 = 1 797 MB. Bu konteynerlar uchun qulay: xotira o'zgarsa, bayroqni qayta yozish kerak emas. Eski Node versiyalarida bu bayroq yo'q — node --help bilan tekshiring.
3.4 Bayroqni berish yo'llari
| Usul | Yozilishi |
|---|---|
| Buyruqda | node --max-old-space-size=2048 server.js |
| Muhit o'zgaruvchisi | NODE_OPTIONS="--max-old-space-size=2048" |
| npm skriptida | "start": "node --max-old-space-size=2048 server.js" |
NODE_OPTIONS qulay: Node'ni bevosita ishga tushirmaydigan vositalarga (masalan next build, vite build) ham ta'sir qiladi. Katta loyihada build "heap out of memory" bilan yiqilsa, birinchi qilinadigan ish — shu.
Tekshirib ko'ring:
--max-old-space-size=1024bilan ishga tushgan Node'daheap_size_limittaxminan qancha bo'ladi?
Javob
Taxminan 1 216 MB: 1 024 (old) + 192 (young, sukut semi-space bilan). Aynan raqam V8 versiyasiga bog'liq, shuning uchun node --max-old-space-size=1024 -p "require('v8').getHeapStatistics().heap_size_limit / 2**20" bilan tekshiring.
4. Chegaraga yetganda
4.1 Tajriba: 64 MB va cheksiz massiv
Kanon tajribasi: heap'ni ataylab kichik qilib (64 MB), cheksiz massivga obyekt qo'shamiz va hammasini try/catch ga o'raymiz. Biz ishga tushirdik (Git Bash). Telefon uchun buyruq uch qatorga bo'lingan: qator oxiridagi \ uni davom ettiradi. PowerShell'da hammasini bitta qatorga yozing.
node --max-old-space-size=64 -e "try { const a = []; \
for (;;) a.push({ x: Math.random(), y: 's'.repeat(50) }) \
} catch (e) { console.log('ushlandi', e.message) }"Chiqishda ikki narsaga qarang: "ushlandi" bormi va oxirgi Mark-Compact qatori qancha MB ni bo'shatdi:
<--- Last few GCs --->
[8180:000001A807CB2000] 393 ms: Mark-Compact 64.0 97.2-bob -> 58.5 127.0-bob MB, pooled: 0 MB, 147.46 / 0.00 ms (average mu = 0.489, current mu = 0.339) allocation failure; scavenge might not succeed
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
----- Native stack trace -----echo $? → 134. "ushlandi" chiqmadi. Nega try/catch ishlamadi?
Heap to'lishi — JS istisnosi emas. V8 ichida obyekt uchun joy topilmaganda, u avval to'liq GC qiladi. Baribir joy bo'lmasa, JS'ga qaytish imkoniyati yo'q: catch blokini bajarish uchun ham xotira kerak. Shuning uchun V8 butun jarayonni abort bilan to'xtatadi. 134 = 128 + 6, SIGABRT signali (process obyekti darsidagi 128 + N kelishuvi).
Last few GCs qismi foydali: oxirgi Mark-Compact 64 MB dan atigi 58,5 MB ga tushirgan. Ya'ni deyarli hamma obyekt tirik edi, tozalaydigan narsa qolmagan. Bu "xotira sizishi" yoki "haqiqatan katta ma'lumot" belgisi.
4.2 Oldini olish
- Hammasini xotiraga yuklamang. 1 GB CSV'ni
readFilebilan emas, oqim bilan bo'lak-bo'lak o'qing (Stream nima). Kanon o'lchovi: 1 mln qatorli CSV — oqim bilan 63 MB, butun fayl bilan 194 MB. - Sizishlarni toping. O'sib boradigan global massiv, unutilgan listener, cheksiz kesh — heap asta to'ladi. Bularni Memory leak'ni topish: heap snapshot darsida ko'rasiz.
- Chegarani ongli qo'ying — konteyner xotirasidan kam, foiz bayrog'i bilan.
- Kuzating —
heapUsedvaqt o'tishi bilan to'xtovsiz o'ssa, bu sizish belgisi.
5. process.memoryUsage() ni o'qish
5.1 Besh maydon
const keys = Object.keys(process.memoryUsage());
console.log(keys.join(", "));Konsolda:
rss, heapTotal, heapUsed, external, arrayBuffers| Maydon | Ma'nosi |
|---|---|
rss |
Resident Set Size — jarayon RAM'da egallagan hamma joy (heap, kod, stack, Buffer…) |
heapTotal |
V8 heap uchun hozir ajratilgan joy |
heapUsed |
heap'ning haqiqatan band qismi (tirik + hali tozalanmagan obyektlar) |
external |
V8 obyektlariga bog'langan, lekin heap'dan tashqaridagi C++ xotira |
arrayBuffers |
ArrayBuffer va Buffer ma'lumoti (external ning bir qismi) |
Kanon o'lchovi — bo'sh skript: rss 37 MB, heapTotal 7 MB, heapUsed 5 MB. Ya'ni Node'ning o'zi RAM'da ~37 MB oladi, JS obyektlari esa atigi 5 MB.
5.2 Bir million obyekt qancha joy oladi
const mb = (b) => `${(b / 2 ** 20).toFixed(1)} MB`;
const before = process.memoryUsage();
const rates = Array.from({ length: 1_000_000 }, (_, i) => ({
kod: "USD",
kurs: 11903.15 + i,
}));
const after = process.memoryUsage();
console.log(
`heapUsed: ${mb(before.heapUsed)} -> ${mb(after.heapUsed)}`,
);
console.log(`rss: ${mb(before.rss)} -> ${mb(after.rss)}`);
console.log(rates.length);Biz ishga tushirdik:
heapUsed: 4.1 MB -> 65.2 MB
rss: 40.4 MB -> 119.3 MB
100000061 MB ÷ 1 000 000 ≈ 64 bayt bitta kichik obyektga (obyekt sarlavhasi, ikkita maydon, kasr son uchun alohida "quti" va massivdagi havola). JSON matni sifatida esa bitta yozuv ~30 bayt. Xotiradagi obyekt matndan ikki baravar og'ir — katta ma'lumotda buni hisobga oling. Bir xil shakldagi obyektlar bitta "yashirin klass"ni bo'lishadi (Hidden classes), shuning uchun shakl o'zgarmasa, ular ixchamroq.
5.3 Buffer heap'dan tashqarida
Muhim nozik joy: Buffer ma'lumoti heap limitiga kirmaydi. Biz ishga tushirdik — heap 64 MB, Buffer esa 500 MB:
const b = Buffer.alloc(500 * 2 ** 20, 1); // 500 MB
const m = process.memoryUsage();
const mb = (x) => (x / 2 ** 20).toFixed(0);
console.log(
`Buffer ${b.length / 2 ** 20} MB | heapUsed ${mb(m.heapUsed)} MB`,
);
console.log(
`arrayBuffers ${mb(m.arrayBuffers)} MB | rss ${mb(m.rss)} MB`,
);node --max-old-space-size=64 buffer.mjs — biz ishga tushirdik:
Buffer 500 MB | heapUsed 4 MB
arrayBuffers 500 MB | rss 531 MBJarayon yiqilmadi: heapUsed 4 MB, ma'lumot esa arrayBuffers da. rss esa 531 MB — RAM'ni haqiqatan oldi. Xulosa: heap limiti "jarayon ko'pi bilan shuncha RAM oladi" degani emas. Konteyner xotirasini rejalashtirishda rss ga qarang. Buffer ni Buffer va binar ma'lumot darsida o'rganasiz.
6. --trace-gc — GC'ni ko'z bilan ko'rish
--trace-gc bayrog'i har GC'ni bitta qator bilan chiqaradi. 300 000 ta obyekt yaratadigan skript — biz ishga tushirdik (dastlabki qatorlar):
const keep = [];
for (let i = 0; i < 300_000; i++) {
keep.push({ kod: "USD", kurs: 11903.15 + i });
}
console.log(keep.length);node --trace-gc gc.mjs — har qatorda -> dan oldingi va keyingi sonlarni solishtiring. Qavs ichidagi sonlar (masalan (28.3)) bo'lim raqami emas, heap uchun ajratilgan joy (MB):
[21244:0000028096F91000] 75 ms: Scavenge 4.9 6.3-bob -> 4.4 7.3-bob MB, pooled: 0 MB, 3.32 / 0.00 ms (average mu = 1.000, current mu = 1.000) allocation failure;
[21244:0000028096F91000] 90 ms: Scavenge 7.2 10.4-bob -> 6.6 14.2-bob MB, pooled: 0 MB, 6.71 / 0.00 ms (average mu = 1.000, current mu = 1.000) allocation failure;
[21244:0000028096F91000] 139 ms: Scavenge 18.8 28.3-bob -> 17.4 45.5-bob MB, pooled: 0 MB, 24.63 / 0.00 ms (average mu = 1.000, current mu = 1.000) allocation failure;Bitta qatorni bo'laklab o'qiymiz:
| Qism | Ma'nosi |
|---|---|
[21244:…] |
PID va ichki identifikator |
139 ms |
jarayon boshidan o'tgan vaqt |
Scavenge |
GC turi (young); Mark-Compact — old |
18.8 28.3-bob -> 17.4 45.5-bob MB |
band (ajratilgan) oldin → keyin |
24.63 / 0.00 ms |
GC davomiyligi |
allocation failure |
sabab: yangi obyektga joy qolmadi |
Bu yerda Scavenge deyarli hech narsani tozalamadi (18,8 → 17,4): hamma obyekt keep massivida tirik. Ular old generation'ga ko'chadi va heap o'sadi. Haqiqiy vaziyatda bunday qatorlar ko'p bo'lsa va Mark-Compact ko'p vaqt olsa — dastur vaqtining katta qismi GC'ga ketyapti.
7. CLI qadami: holat yo'q
valyuta ga bu darsdan kod qo'shilmaydi — o'lchov shuni ko'rsatdi:
- CLI'ning eng katta ma'lumoti — 74 ta kurs (25,5 KB JSON). Bir million obyekt ~61 MB bo'lsa, 74 tasi — kilobaytlar.
- Bo'sh Node 37 MB
rssoladi;valyutauning ustiga deyarli hech narsa qo'shmaydi. Sukut 4 GB limitga yaqinlashish imkoni yo'q.
Lekin keyinroq valyuta 1 million qatorli CSV yasaydi (Amaliyot: katta faylni stream bilan). U yerda bu darsdagi memoryUsage() bilan o'lchab, butun faylni xotiraga yig'ish (194 MB) va oqim (63 MB) farqini o'z ko'zingiz bilan ko'rasiz.
8. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
JavaScript heap out of memory, exit 134 |
heap chegarasi to'ldi | ma'lumotni oqim bilan; sizishni toping; kerak bo'lsa limitni oshiring |
try/catch OOM'ni ushlamadi |
OOM — JS istisnosi emas, abort |
xotirani oldindan nazorat qiling |
| Konteyner o'ldirildi, Node xato yozmadi | heap + Buffer + kod > konteyner xotirasi | old-space'ni konteynerdan kam qo'ying, rss ni kuzating |
--max-old-space-size=512, lekin heap 704 MB |
young generation qo'shiladi | heap_size_limit ni o'lchang |
next build OOM bilan yiqildi |
build vositasi ham Node | NODE_OPTIONS=--max-old-space-size=… |
RangeError: Maximum call stack size exceeded |
cheksiz/juda chuqur rekursiya | sikl yoki to'xtash sharti; bu heap emas, stack |
9. Mashqlar
Mashqlar kurs/mashqlar/24/09-xotira/ da.
1-mashq (oson): qaysi maydon?
- Butun jarayon RAM'da qancha joy olgani —
- JS obyektlari haqiqatan egallagan heap —
Buffer.alloc(10_000_000)ma'lumoti qayerda hisoblanadi —- Yangi obyektlar yashaydigan avlod — generation
- Old generation'ni tozalaydigan GC — Mark-Sweep-
Yechim
- rss — heap, kod, stack, Buffer — hammasi.
- heapUsed —
heapTotaldan kichik; farqi — ajratilgan, lekin bo'sh joy. - arrayBuffers — u
externalichida ham hisoblanadi; heap limitiga kirmaydi. - young — Scavenge tozalaydi.
- Compact — belgilash, tozalash, zichlash.
2-mashq (o'rta): limitni oldindan hisoblang
O'lchovdan chiqqan qonuniyat: heap_size_limit ≈ old + 3 × semi (MB). Sukut semi — 64 MB. predictLimit(oldMb, semiMb = 64) funksiyasini yozing va jadvaldagi uchta o'lchov bilan solishtiring: (256) → 448, (8192) → 8384, (256, 16) → 304. Har qator uchun mos yoki mos emas chiqaring.
Yechim
function predictLimit(oldMb, semiMb = 64) {
return oldMb + 3 * semiMb;
}
const measured = [
{ args: [256], limit: 448 },
{ args: [8192], limit: 8384 },
{ args: [256, 16], limit: 304 },
];
for (const m of measured) {
const p = predictLimit(...m.args);
const ok = p === m.limit ? "mos" : "mos emas";
console.log(`${m.args.join(", ")}: ${p} — ${ok}`);
}Konsolda:
256: 448 — mos
8192: 8384 — mos
256, 16: 304 — mosUchala o'lchov formulaga mos. Lekin bu — bitta mashina va bitta V8 versiyasidagi kuzatuv, kafolatlangan qoida emas. V8 yangilanganda o'zgarishi mumkin, shuning uchun production'da baribir heap_size_limit ni o'lchang.
3-mashq (qiyin): xotira hisoboti
Node skripti yozing: report(label) — process.memoryUsage() dan heapUsed va arrayBuffers ni MB'da (bir xona kasr bilan) va v8.getHeapStatistics() dan limitni (butun MB) bitta qatorda chiqarsin. Uni uch marta chaqiring: boshida, 200 000 obyekt yaratgandan keyin va 50 MB Buffer yaratgandan keyin. Natijada arrayBuffers faqat oxirgi qadamda o'sganini, heapUsed esa ikkinchi qadamda o'sganini tekshiring — buni true/false bilan chiqaring.
Yechim
import v8 from "node:v8";
const toMb = (b) => Math.round((b / 2 ** 20) * 10) / 10;
function report(label) {
const m = process.memoryUsage();
const { heap_size_limit } = v8.getHeapStatistics();
const limit = Math.round(heap_size_limit / 2 ** 20);
const heap = toMb(m.heapUsed);
return { label, heap, buffers: toMb(m.arrayBuffers), limit };
}
const start = report("boshida");
const objects = Array.from({ length: 200_000 }, (_, i) => ({ i }));
const afterObjects = report("obyektlar");
const buf = Buffer.alloc(50 * 2 ** 20);
const afterBuffer = report("buffer");
console.log(afterObjects.heap - start.heap > 3);
console.log(afterObjects.buffers - start.buffers < 1);
console.log(afterBuffer.buffers - afterObjects.buffers >= 50);
console.log(objects.length, buf.length / 2 ** 20);Konsolda:
true
true
true
200000 50Raqamlarning o'zi (masalan heap: 9.8) har kompyuterda boshqa, shuning uchun mashq farqlarni tekshiradi. 200 000 obyekt heap'ni bir necha MB oshiradi, arrayBuffers ga tegmaydi. 50 MB Buffer esa aksincha. Oxirgi qator obyektlar va buffer'ni "tirik" ushlab turadi — aks holda GC ularni o'lchovdan oldin tozalashi mumkin edi.
10. Real ishda
- Konteynerlar — Docker va Kubernetes'da xotira chegarasi bor; Node heap'i va
rssuni hisobga olishi kerak. Node sukut limitida konteyner (cgroup) chegarasini qanchalik hisobga olishi versiyaga bog'liq — biz Linux konteynerda sinamadik. Shuning uchun bayroqni (yoki foiz bayrog'ini) aniq qo'yish ishonchliroq. - Build vositalari — katta TypeScript yoki Next.js loyihada
tscvanext buildOOM bilan yiqilishi odatiy hol; yechim —NODE_OPTIONS=--max-old-space-size=4096va build'ni bo'lish. - Monitoring — production'da
heapUsedvarssgrafigi kuzatiladi. "Arra tishi" (o'sib, GC'da tushadi) — normal. To'xtovsiz o'sish — sizish (Memory leak'ni topish). - Intervyu savoli: "Node'da heap out of memory'ni qanday hal qilasiz?" — avval sababini aniqlash (katta ma'lumot yoki sizish), keyin oqim/paginatsiya, oxirida limitni oshirish.
Xulosa
- V8 heap'i avlodlarga bo'lingan: young (Scavenge, tez) va old (Mark-Sweep-Compact, og'irroq).
- Sukut limit RAM'ga bog'liq: 16 GB'da 4 288 MB;
--max-old-space-sizefaqat old qismini beradi, young (192 MB) ustiga qo'shiladi. - Chegaraga yetganda —
FATAL ERROR: … heap out of memory, exit 134;try/catchushlamaydi. memoryUsage():rss— butun jarayon,heapUsed— JS obyektlari,arrayBuffers— Buffer (heap limitidan tashqarida).--trace-gchar GC'ni ko'rsatadi; ko'p va uzoqMark-Compact— muammo belgisi.
Keyingi dars: CommonJS ichidan: module wrapper, resolution va circular require — require faylni qanday topadi, nimaga o'raydi va sikl bo'lsa nima beradi.
Manbalar
- Node.js hujjati —
--max-old-space-size,--max-old-space-size-percentage,--max-semi-space-size: https://nodejs.org/docs/latest-v24.x/api/cli.html - Node.js hujjati —
v8.getHeapStatistics,v8.getHeapSpaceStatistics: https://nodejs.org/docs/latest-v24.x/api/v8.html - Node.js hujjati —
process.memoryUsage(): https://nodejs.org/docs/latest-v24.x/api/process.html#processmemoryusage - V8 blogi — Trash talk: the Orinoco garbage collector: https://v8.dev/blog/trash-talk
- Node.js qo'llanmasi — Understanding and Tuning Memory: https://nodejs.org/en/learn/diagnostics/memory/understanding-and-tuning-memory
- Kanon:
valyutatajribasi — heap limitlari, 64 MB OOM (exit 134), bo'sh skriptmemoryUsage(Node 24.21.0, Windows 11, 16 GB RAM, 2026-10-23); semi-space, percentage, Buffer,--trace-gc, stack chuqurligi — yozuvchi o'lchovi, xuddi shu mashina.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!