JavaScriptda xotira boshqaruvi(Garbage Collection)

JavaScript-da xotira boshqaruvi avtomatik ravishda amalga oshiriladi va bu jarayon biz uchun ko'rinmasdir. Biz primitivlar, obyektlar, funksiyalar yaratamiz... Bularning barchasi xotira talab qiladi.

Garbage Collection

JavaScript-da xotira boshqaruvi avtomatik ravishda amalga oshiriladi va bu jarayon biz uchun ko'rinmasdir. Biz primitivlar, obyektlar, funksiyalar yaratamiz... Bularning barchasi xotira talab qiladi.

Nimadir kerak bo'lmay qolganda nima sodir bo'ladi? JavaScript dvigateli buni qanday aniqlaydi va xotirani qanday tozalaydi?

Kirish mumkinlik

JavaScript-da xotira boshqaruvining asosiy konsepsiyasi kirish mumkinlik (reachability) hisoblanadi.

Oddiy qilib aytganda, “kirish mumkin” qiymatlar qandaydir tarzda kirish mumkin bo‘lgan yoki foydalanilishi mumkin bo‘lgan qiymatlardir. Ular xotirada saqlanishi kafolatlanadi.

Kirishi mumkin bo'lgan qiymatlarning asosiy to'plami mavjud bo'lib, ularni yo'q qilish mumkin emasligi aniq sabablarga ko'ra amalga oshirilmaydi.

Masalan:

  • Hozirda bajarilayotgan funksiya, uning lokal o'zgaruvchilari va parametrlari.
  • Joriy chaqiriqlar zanjiridagi boshqa funksiyalar, ularning lokal o'zgaruvchilari va parametrlari.
  • Global o'zgaruvchilar.
  • (yana ba'zi boshqa ichki qiymatlar ham mavjud)

Ushbu qiymatlar "ildizlar" deb ataladi.

Ildizdan havola yoki havolalar zanjiri orqali kirish mumkin bo'lsa, har qanday boshqa qiymat kirish mumkin deb hisoblanadi.

Masalan, agar global o'zgaruvchida obyekt bo'lsa va bu obyekt boshqa obyekti ko'rsatadigan xususiyatga ega bo'lsa, bu obyekt kirish mumkin deb hisoblanadi. Va u ko'rsatadigan obyektlar ham kirish mumkin bo'ladi. Bunga misollar quyida keltiriladi.

JavaScript dvigatelida fon jarayoni mavjud bo'lib, u "garbage collector" deb ataladi. U barcha obyektlarni kuzatib boradi va kirish mumkin bo'lmagan obyektlarni olib tashlaydi.

Oddiy misol

Mana eng oddiy misol:

// user obyektga havola qiladi
let user = {
  name: 'John',
};
Memory user john

Bu erda o'q obyektga havolani ko'rsatadi. Global o'zgaruvchi user {name: "John"} obyektiga havola qiladi (qisqacha John deb ataymiz). Johnning "name" xususiyati primitiv qiymatni saqlaydi, shuning uchun u obyekt ichida tasvirlangan.

Agar user qiymati qayta yozilsa, havola yo'qoladi:

user = null;
Memory user john lost

Endi John kirish mumkin bo'lmaydi. Uni kirishning hech qanday usuli yo'q, unga hech qanday havola yo'q. Garbage collector ma'lumotlarni yo'q qiladi va xotirani bo'shatadi.

Ikki havola

Endi userdan adminga havolani nusxa ko'chirganimizni tasavvur qilaylik:

// user obyektga havola qiladi
let user = {
  name: 'John',
};
 
let admin = user;
Memory user john admin

Endi xuddi shunday qilsak:

user = null;

...Unda obyekt hali ham admin global o'zgaruvchisi orqali kirish mumkin bo'ladi, shuning uchun u xotirada qolishi kerak. Agar adminni ham qayta yozsak, unda u ham olib tashlanadi.

O'zaro bog'langan obyektlar

Endi murakkabroq misol. Oila:

function marry(man, woman) {
  woman.husband = man;
  man.wife = woman;
 
  return {
    father: man,
    mother: woman,
  };
}
 
let family = marry(
  {
    name: 'John',
  },
  {
    name: 'Ann',
  }
);

marry funksiyasi ikki obyektni o'zaro havolalar orqali "nikohlantiradi" va ularni o'z ichiga olgan yangi obyektni qaytaradi.

Hosil bo'lgan xotira tuzilishi:

Family

Hozirda barcha obyektlar kirish mumkin.

Endi ikkita havolani olib tashlaymiz:

delete family.father;
delete family.mother.husband;
Family delete refs

Faqat bitta ushbu ikkita havolani o'chirish yetarli emas, chunki barcha obyektlar hali ham kirish mumkin bo'lardi.

Ammo agar ikkisini ham o'chirsak, John endi kirish mumkin bo'lmay qoladi, chunki unga hech qanday kiruvchi havola yo'q:

Family no father

Chiquvchi havolalar muhim emas. Faqat kiruvchi havolalar obyektni kirish mumkin qilishi mumkin. Shunday qilib, John endi kirish mumkin bo'lmaydi va uning barcha ma'lumotlari bilan birga xotiradan o'chiriladi.

Family no father

Kirish mumkin bo'lmagan orol

Butun bir o'zaro bog'langan obyektlar oroli kirish mumkin bo'lmay qolishi va xotiradan olib tashlanishi mumkin.

Manba obyekt yuqoridagi bilan bir xil. Keyin:

family = null;
Family no family

Xotiradagi rasm quyidagicha bo'ladi:

Bu misol kirish mumkinlik konsepsiyasining qanchalik muhimligini ko'rsatadi.

John va Ann hali ham bog'langan, ikkalasi ham kiruvchi havolalarga ega ekanligi aniq. Lekin bu yetarli emas.

Ilgari family obyekt ildizidan uzildi, endi unga hech qanday havola yo'q, shuning uchun butun orol kirish mumkin bo'lmaydi va olib tashlanadi.

Ichki algoritmlar

Asosiy garbage collection algoritmi “belgilash-va-tozalash” (mark-and-sweep) deb ataladi.

Quyidagi “garbage collection” bosqichlari muntazam ravishda bajariladi:

  1. Garbage collector ildizlarni oladi va ularni "belgilaydi" (eslab qoladi).
  2. Keyin u ularning barcha havolalarini ko'rib chiqadi va belgilaydi.
  3. Keyin belgilangan obyektlarni ko'rib chiqadi va ularning havolalarini belgilaydi. Barcha tashrif buyurilgan obyektlar eslab qolingan bo'ladi, shuning uchun kelajakda bir xil obyekti ikki marta ko'rib chiqilmaydi.
  4. …Va bu jarayon barcha kirish mumkin bo'lgan (ildizlardan) havolalar tashrif buyurilguniga qadar davom etadi.
  5. Belgilanganlardan tashqari barcha obyektlar olib tashlanadi.

Misol uchun, obyektlar tuzilmasi quyidagicha bo'lsin:

Garbage collection

Biz aniq ko'rishimiz mumkin bo'lgan "kirish mumkin bo'lmagan orol" o'ng tomonda. Endi “belgilash-va-tozalash” garbage collectori uni qanday hal qilishini ko'rib chiqamiz.

Birinchi bosqich ildizlarni belgilaydi:

Garbage collection

Keyin ularning havolalariga ergashib, havola qilingan obyektlarni belgilaymiz:

Garbage collection

…Va imkon qadar keyingi havolalarni kuzatishda davom etamiz:

Garbage collection

Endi bu jarayonda tashrif buyurilmagan obyektlar kirish mumkin bo'lmagan deb hisoblanadi va olib tashlanadi:

Garbage collection

Biz bu jarayonni ildizlardan katta bo'yoq paqirini to'kib, barcha havolalar orqali oqib o'tayotganini va barcha kirish mumkin bo'lgan obyektlarni belgilayotganini tasavvur qilishimiz mumkin. Belgilanmaganlari keyin olib tashlanadi.

Bu garbage collection qanday ishlashining konsepsiyasidir. JavaScript dvigatellari uni tezroq ishlatish va kodni bajarishda kechikishlarni kiritmaslik uchun ko'plab optimallashtirishlarni qo'llaydi.

Ba'zi optimallashtirishlar:

  • Avlodlar bo'yicha yig'ish – obyektlar ikki to'plamga bo'linadi: "yangi" va "eski". Oddiy kodda ko'plab obyektlar qisqa umr ko'radi: ular paydo bo'ladi, o'z ishini bajaradi va tezda "o'ladi", shuning uchun yangi obyektlarni kuzatib borish va xotirani tozalash mantiqiydir. Ular yetarlicha uzoq yashasa, "eski" bo'lib, kamroq tekshiriladi.
  • Bosqichma-bosqich yig'ish – agar ko'plab obyektlar mavjud bo'lsa va biz bir vaqtning o'zida barcha obyektlarni belgilash va tekshirishga harakat qilsak, bu vaqt talab qilishi va bajarilishida sezilarli kechikishlarni kiritishi mumkin. Shunday qilib, dvigatel mavjud obyektlar to'plamini bir nechta qismga bo'ladi. Va keyin bu qismlarni birma-bir tozalaydi. Katta yig'ish o'rniga ko'plab kichik garbage collectionlar mavjud. Bu yig'

ishlar orasida o'zgarishlarni kuzatish uchun qo'shimcha qaydlar talab qiladi, lekin biz katta kechikish o'rniga ko'plab kichik kechikishlarga ega bo'lamiz.

  • Bo'sh vaqt yig'ish – garbage collector CPU bo'sh turganda faqat ishlashga harakat qiladi, bu bajarishga ta'sirini kamaytirish uchun.

Boshqa optimallashtirishlar va garbage collection algoritmlarining turli xil versiyalari mavjud. Bularni bu yerda tavsiflash juda qiziqarli bo'lsa-da, turli dvigatellar turli xil o'zgarishlar va usullarni amalga oshiradi, shuning uchun ularni chuqurroq o'rganish hojat bo'lmasligi mumkin. Albatta, bu sof qiziqish masalasi bo'lmasa. Agar shunday bo'lsa, quyida ba'zi havolalar beriladi.

Xulosa

Asosiy bilishingiz kerak bo'lgan narsalar:

  • Garbage collection avtomatik ravishda amalga oshiriladi. Biz uni majburlay olmaymiz yoki oldini olmaymiz.
  • Obyektlar xotirada saqlanadi, ular kirish mumkin bo'lsa.
  • Havola qilingan obyekt ildizdan kirish mumkin bo'lmasligi mumkin: o'zaro bog'langan obyektlar to'plami butunligicha kirish mumkin bo'lmay qolishi mumkin, yuqoridagi misolda ko'rganimizdek.
  • Zamonaviy dvigatellar garbage collectionning ilg'or algoritmlarini amalga oshiradi.

"Garbage Collection Handbook: The Art of Automatic Memory Management" (R. Jones va boshqalar) kabi umumiy kitob ba'zi birlarini qamrab oladi.

Agar past darajadagi dasturlash bilan tanish bo'lsangiz, V8 garbage collector haqida ko'proq ma'lumotni "A tour of V8: Garbage Collection" maqolasida topishingiz mumkin.

V8 blogi vaqti-vaqti bilan xotira boshqaruviga oid maqolalarni nashr etadi. Tabiiyki, garbage collection haqida ko'proq bilishni istasangiz, V8 ichki qismlarini umumiy o'rganish va V8 muhandislaridan biri bo'lgan Vyacheslav Egorovning blogini o'qish yaxshiroq bo'ladi. “V8”ni tilga olayotganim sababi, u internetdagi maqolalarda yaxshi yoritilgan. Boshqa dvigatellarda ko'plab yondashuvlar o'xshash bo'lsa-da, garbage collection ko'p jihatdan farq qiladi.

Dvigatellarni chuqur bilish past darajadagi optimallashtirishlarga muhtoj bo'lganda foydali bo'ladi. Bu til bilan tanishganingizdan keyin rejalashtirishda oqilona bo'lar edi.

Ushbu sahifada

GitHubda tahrirlash