Garbage Collection — xotira qanday tozalanadi, Memory Leak

~15 daq · JavaScript · Ilg'or mavzular

Muammodan boshlaylik

Siz uzoq vaqt ishlaydigan veb ilova yozdingiz — admin panel, dashboard. Boshida tez ishlaydi. 30 daqiqadan keyin sekinlashadi. Bir soatdan keyin brauzer "sahifa ko'p xotira sarflayapti" deydi.

Kod to'g'ri ishlaydi. Xato chiqmaydi. Lekin xotira ozayib boradi. Bu — Memory Leak (xotira oqishi).

Memory Leak ni tushunish uchun — JavaScript xotirani qanday boshqarishini tushunish kerak.


JavaScript xotirani qanday boshqaradi?

JavaScript avtomatik xotira boshqaruviga ega. Siz malloc/free (C dagi kabi) yozmasiz. JavaScript o'zi xotira ajratadi va kerak bo'lmaganda tozalaydi.

Bu tozalash jarayoni — Garbage Collection (axlat yig'ish).

Hayotiy o'xshatma

Mehmonxona xodimi. Mehmon ketgandan keyin — xona tozalanadi, yangi mehmon uchun tayyorlanadi. Lekin xodim faqat haqiqatan bo'sh xonalarni tozalaydi. Agar biror mehmonning jihozi xonada qolgan bo'lsa — "hali band" deb hisoblanadi.

Garbage Collector — o'sha xodim. Ob'ektga reference qolmagan bo'lsa — "bo'sh" deb tozalaydi.


Reachability — yetib borish mumkinmi?

Garbage Collector bir savolni beradi: "Ushbu ob'ektga yetib borish mumkinmi?"

"Yetib borish mumkin" — bu global o'zgaruvchilar, joriy chaqiruv steki, yoki ulardan zanjirlanib borilishi mumkin ob'ektlar.

let foydalanuvchi = { ism: "Jasur" };
// { ism: "Jasur" } — yetib borish mumkin, foydalanuvchi orqali

foydalanuvchi = null;
// { ism: "Jasur" } — endi yetib borib bo'lmaydi, reference yo'q
// Garbage Collector tozalaydi

Ikki ob'ekt bir-biriga reference ushlab tursa ham — agar tashqaridan yetib borish mumkin bo'lmasa, tozalanadi:

function yaratishVaYo_qotish() {
  const a = { nomi: "A" };
  const b = { nomi: "B" };

  a.hamkor = b; // a → b
  b.hamkor = a; // b → a — bir-biriga reference

  // Funksiya tugaydi — a va b lokal o'zgaruvchilar yo'qoladi
  // Tashqaridan yetib bo'lmaydi — ikkisi ham tozalanadi
}

Memory Leak — xotira tozalanmaydi

Memory Leak — ob'ektlarga reference saqlanib qoladi, lekin ular endi kerak emas. Garbage Collector tozalay olmaydi — chunki "yetib borish mumkin".

Eng ko'p uchraydigan hollar

1. Global o'zgaruvchi — intentional emas:

function hisobla() {
  natija = []; // ← `let`/`const` yo'q — global o'zgaruvchi yaratildi!
  for (let i = 0; i < 100000; i++) {
    natija.push({ id: i, ma'lumot: new Array(1000).fill("x") });
  }
}

hisobla();
// natija — global, hech qachon tozalanmaydi

Har funksiya chaqiruvida massiv kattalashib boradi. "use strict" bu xatoni oldini oladi.

2. Unutilgan interval:

function boshlash() {
  const katta_massiv = new Array(100000).fill("x");

  setInterval(function() {
    console.log(katta_massiv.length); // ← katta_massiv ga reference
  }, 1000);
}

boshlash();
// setInterval to'xtatilmadi — katta_massiv hech qachon tozalanmaydi

Hayotiy o'xshatma

Mehmonxona jihozi. Mehmon chiqib ketdi — lekin jihozi xonada qoldi. Xona "band" deb hisoblanadi. Keyin yana mehmon chiqib ketdi — yana jihozi qoldi. Mehmonxona to'lib boradi, bo'sh xona qolmaydi. Bu — Memory Leak.

// ✅ — intervallarni to'xtatish
function boshlash() {
  const massiv = new Array(100000).fill("x");
  const intervalId = setInterval(function() {
    console.log(massiv.length);
  }, 1000);

  return function to'xtatish() {
    clearInterval(intervalId); // ← tozalash
  };
}

const to'xtat = boshlash();
// ... keyin ...
to'xtat(); // ← interval to'xtatildi, massiv tozalanishi mumkin

3. Unutilgan event listener:

function komponentYarat() {
  const kattaMa'lumot = new Array(100000).fill("x");

  document.addEventListener("click", function handler() {
    console.log(kattaMa'lumot[0]);
  });

  // handler va kattaMa'lumot — hech qachon tozalanmaydi!
}

// Komponent 100 marta yaratilsa — 100 ta handler, 100 ta kattaMa'lumot
komponentYarat();
komponentYarat();
// ...
// ✅ — listener ni olib tashlash
function komponentYarat() {
  const kattaMa'lumot = new Array(100000).fill("x");

  function handler() {
    console.log(kattaMa'lumot[0]);
  }

  document.addEventListener("click", handler);

  return function tozalash() {
    document.removeEventListener("click", handler); // ← olib tashlash
  };
}

const tozala = komponentYarat();
// ... keyin komponent o'chirilganda ...
tozala();

4. Map / Set da ob'ektlarni saqlab qolish:

Oldingi darsda ko'rgan holat — Map dagi reference ob'ektni "ushlab turadi".

const kesh = new Map();

function ma'lumotOl(id) {
  const ob = { id, ma'lumot: new Array(10000).fill("x") };
  kesh.set(id, ob); // ← kesh reference ushlab turadi
  return ob;
}

// Har chaqiruvda yangi ob'ekt keshga qo'shiladi — hech biri ketmaydi
for (let i = 0; i < 10000; i++) {
  ma'lumotOl(i);
}
// kesh 10,000 katta ob'ektni ushlab turadi

// ✅ — kesh hajmini cheklash yoki WeakMap ishlatish

Closure va Memory Leak

Closure — tashqi o'zgaruvchiga reference ushlab turadi. Ba'zan bu kerakmas ma'lumotni saqlab qolishi mumkin:

function kattaFunksiya() {
  const kattaMassiv = new Array(1000000).fill("x"); // 1 million element

  return function kichik() {
    return "men kichikman";
    // kattaMassiv ishlatilmaydi — lekin closure ushlab turadi!
  };
}

const fn = kattaFunksiya();
// fn — kichik funksiya, lekin kattaMassiv xotirada
// ✅ — kerak bo'lmagan ma'lumotni null qilish
function kattaFunksiya() {
  let kattaMassiv = new Array(1000000).fill("x");
  const natija = kattaMassiv.length; // faqat natija kerak

  kattaMassiv = null; // ← endi reference yo'q, tozalanishi mumkin

  return function() {
    return natija; // natija — kichik son, katta massiv emas
  };
}

Memory Leak ni aniqlash

Chrome DevTools Memory panel — xotirani kuzatish:

  1. DevTools → Memory
  2. "Take heap snapshot" — hozirgi xotira surati
  3. Bir muddat kutish (ilova ishlaydi)
  4. Yana "Take heap snapshot"
  5. Ikki suratsni solishtirish — qaysi ob'ektlar ko'paygan?

Yoki Performance panel → "Record" — vaqt o'tishi bilan xotira grafigi.


Tez-tez uchraydigan xatolar

let/const o'rniga global o'zgaruvchi:

// ❌ — global yaratildi (strict modeda xato)
function f() { natija = []; }

// ✅
function f() { const natija = []; }

Component o'chirilganda tozamaslik:

React, Vue kabi frameworklarda component o'chirilganda — useEffect cleanup, beforeUnmount hook larda intervallar, listener lar to'xtatilishi shart.


Xulosa

Garbage Collection — JavaScript avtomatik xotira tozalash. Ob'ektga yetib borish mumkin bo'lmasa — tozalanadi.

Memory Leak — reference saqlanib qoladi, ob'ekt kerak emas — lekin tozalanmaydi.

Asosiy sabablar:

  • Kutilmagan global o'zgaruvchilar
  • Tozalanmagan setInterval
  • Olib tashlanmagan event listener lar
  • Map/Set da keraksiz ob'ektlar (WeakMap ishlatish)

Ilova sekin bo'lib borsa — DevTools Memory panel da memory leak qidiring.


Keyingi dars

66-dars: Funksional dasturlash nima va nima uchun kerak