Obyektlar: asoslar

Axlat yig'ish (Garbage collection)

JavaScript'da xotira boshqaruvi avtomatik va ko'zga ko'rinmas tarzda amalga oshiriladi. Biz o'zgaruvchilar, obyektlar, funksiyalar yaratamiz โ€” bularning hammasi xotira egallaydi. Endi savol: kerak bo'lmay qolgan narsalar bilan nima bo'ladi? Buni axlat yig'uvchi (garbage collector) hal qiladi.

Erishuvchanlik (Reachability)

JavaScript'dagi xotira boshqaruvining asosiy tushunchasi โ€” erishuvchanlik (reachability). Sodda qilib aytganda, "erishsa bo'ladigan" qiymatlar โ€” bu qandaydir yo'l bilan ishlatilishi mumkin bo'lgan qiymatlar. Ular xotirada saqlanib qoladi.

Erishsa bo'ladigan qiymatlar to'plami mavjud. Ba'zi qiymatlar ta'rifga ko'ra erishsa bo'ladigan hisoblanadi. Bularni root (ildiz) deb ataymiz:

Asosiy qoida shunday: agar biror qiymatga rootdan havola yoki havolalar zanjiri orqali yetib borilsa โ€” u erishsa bo'ladigan (kerakli) hisoblanadi va saqlanadi. Aks holda โ€” u "axlat" va tozalanadi.

Fonda uzluksiz ishlaydigan maxsus jarayon โ€” garbage collector (axlat yig'uvchi) โ€” barcha obyektlarni kuzatib turadi, erishib bo'lmaydiganlarini topadi va o'chiradi.

Oddiy misol

Global o'zgaruvchida obyektga havola bor:

// user global o'zgaruvchisi obyektga havola qiladi
let user = {
  name: "Jaloliddin"
};

Bu yerda user obyektga ("strelka") havola qiladi. Obyektning name xossasi primitivni saqlaydi. Agar user qiymatini boshqasiga o'zgartirsak, havola yo'qoladi:

user = null;

// Endi "Jaloliddin" obyektiga hech qanday havola yo'q.
// Unga erishib bo'lmaydi โ€” garbage collector uni o'chiradi,
// xotira bo'shatiladi.

Ikkita havola

Endi bir obyektga ikkita havola bo'lsa, vaziyat o'zgaradi:

let user = {
  name: "Jaloliddin"
};

let admin = user; // ikkinchi havola

Agar endi userni null qilsak:

user = null;

Obyekt hamon erishsa bo'ladigan bo'lib qoladi, chunki unga admin orqali yetib borilyapti. U xotirada saqlanadi. Faqat admin = null ham qilsak, obyekt erishib bo'lmaydigan bo'ladi va o'chiriladi.

O'zaro bog'langan obyektlar

Endi murakkabroq misol โ€” bir-biriga havola qiluvchi obyektlar. Bir oila obyektini tasavvur qiling:

function marry(man, woman) {
  woman.husband = man;
  man.wife = woman;

  return {
    father: man,
    mother: woman
  };
}

let family = marry(
  { name: "Sardor" },
  { name: "Nilufar" }
);

Natijada obyektlar bir-biriga havola qiladi: family ikkalasiga, father va mother esa husband/wife orqali o'zaro bog'langan. Barcha obyektlarga family (root)dan yetib boriladi โ€” hammasi erishsa bo'ladigan.

Endi ikkita havolani olib tashlaymiz:

delete family.father;
delete family.mother.husband;

"Sardor" (father) obyektiga endi hech qanday kiruvchi havola qolmadi: family.father o'chirildi, woman.husband ham. Uning ichidan tashqariga havolalar bo'lishi (masalan, u wifega havola qilishi) ahamiyatsiz โ€” muhimi unga tashqaridan yetib bo'lmasligi. Shu sabab "Sardor" obyekti o'chiriladi.

Diqqat: erishuvchanlik faqat kiruvchi havolalar bilan aniqlanadi. Obyektning boshqalarga havola qilishi uni saqlab qolmaydi โ€” unga root'dan yetib borish kerak.

Yetib bo'lmaydigan orol

Bir butun bog'langan obyektlar guruhi ham axlatga aylanishi mumkin โ€” agar butun guruhga tashqaridan yetib bo'lmasa. Agar family = null qilsak, ichkarida obyektlar bir-biriga havola qilib tursa ham, ularga root'dan yo'l yo'q. Shunday "orol" butunligicha o'chiriladi.

Bu muhim: obyektlarning o'zaro bog'langani ularni saqlab qolmaydi. Agar butun bir tarmoqqa root'dan yetib bo'lmasa, u to'liq tozalanadi.

Ichki algoritm: mark-and-sweep

Asosiy axlat yig'ish algoritmi "mark-and-sweep" (belgila va tozala) deb ataladi. U taxminan quyidagicha ishlaydi:

  1. Garbage collector root'larni oladi va ularni "belgilaydi" (eslab qoladi);
  2. So'ng root'lardan havola qilinayotgan barcha obyektlarga tashrif buyurib, ularni belgilaydi;
  3. So'ng belgilangan obyektlarga tashrif buyuradi va ular havola qilayotganlarni belgilaydi. Barcha yo'llar to'liq ko'rilguncha bu davom etadi;
  4. Belgilanmagan barcha obyektlar โ€” erishib bo'lmaydigan hisoblanadi va o'chiriladi (xotira bo'shatiladi).

Buni bo'yoq to'kilishiga o'xshatish mumkin: root'dan boshlab, havolalar bo'ylab "bo'yoq" tarqaladi. Bo'yoq yetib bormagan (belgilanmagan) obyektlar โ€” erishib bo'lmaydigan va o'chiriladi.

Optimallashtirishlar

Zamonaviy dvigatellar axlat yig'ishni tezlashtirish uchun ilg'or usullar qo'llaydi:

Bu optimallashtirishlar ichki tafsilotlar โ€” ular vaqt o'tishi bilan o'zgaradi. Kundalik dasturlashda ularni yodda tutish shart emas; dvigatel o'zi hal qiladi.

Xulosa