JavaScript-da xotirani boshqarish biz uchun avtomatik va koârinmas holda amalga oshiriladi. Biz ibtidoiylarni, obâektlarni, funktsiyalarni yaratamiz⊠Barchasi xotirani talab qiladigan narsa.
Biror narsa kerak boâlmaganda nima boâladi? JavaScript interpretatori uni qanday kashf etadi va tozalaydi?
Erishish imkoniyati
JavaScript-da xotirani boshqarishning asosiy kontseptsiyasi bu uning erishish imkoniyati.
Oddiy qilib aytganda, âerishish mumkinâ qiymatlar â bu kirish imkoniyati yoki qandaydir tarzda foydalanish mumkin boâlgan qiymatlar. Ularning xotirada saqlanishi kafolatlangan.
-
Muayyan sabablarga koâra oâchirib boâlmaydigan tabiiy ravishda erishiladigan qiymatlarning asosiy toâplami mavjud.
Masalan:
- Joriy funktsiyalarning ichki oâzgaruvchanlari va parametrlari.
- Ichki chaqiruvlarning joriy zanjiridagi boshqa funktsiyalarning oâzgaruvchanlari va parametrlari.
- Global oâzgaruvchanlar.
- (baâzi bir ichki narsalar ham bor)
Ushbu qiymatlar ildizlar deb nomlanadi.
-
Agar istalgan maâlumotga havolalar zanjiri orqali ildizdan erishish mumkin boâlsa, bu qiymat erishuvchi deb hisoblanadi.
Masalan, agar ichki oâzgaruvchanda obâekt mavjud boâlsa va u boshqa obâektga tegishli xususiyatga ega boâlsa, u obâektga erishish mumkin deb hisoblanadi. Va u qilgan havolalar ham erishuvchan. Batafsil misollar quyida.
JavaScript dvigatelida axlat yigâuvchi deb nomlangan fon jarayoni mavjud. U barcha obâektlarni kuzatib boradi va erishib boâlmaydigan narsalarni olib tashlaydi.
Oddiy misol
Mana eng oddiy misol:
// foydalanuvchi ob'ektga havolaga ega
let user = {
name: "John",
};
Bu yerda oâq obâektga havola koârsatadi. "user" ning global oâzgaruvchani {name: "John"} obâektiga ishora qiladi (biz uni John deb ataymiz). John obâektining "name" xususiyatida primitiv saqlanadi, shuning uchun u obâekt ichida chizilgan.
Agar user qiymati qayta yozilsa, havola yoâqoladi:
user = null;
Endi Jonga yetib boâlmaydi. Unga kirishning imkoni yoâq, unga havolalar yoâq. Axlat yigâuvchi maâlumotlar axlatini va xotirani boâshatadi.
Ikkita havolalar
Endi user dan admin ga havolani koâchirib olganimizni tasavvur qilaylik:
// user ob'ektga havolaga ega
let user = {
name: "John"
};
let admin = user;
Endi biz ham xuddi shunday qilsak:
user = null;
âŠHozir obâektga admin global oâzgaruvchani orqali kirish mumkin, shuning uchun u xotirada. Agar biz admin ning qayta yozsak, u oâchirilishi mumkin.
Oâzaro bogâlangan obâektlar
Endi yanada murakkab 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 funktsiyasi ikkita obâektni birlashtiradi, ularni bir-biriga bogâlaydi va ikkalasini ham oâz ichiga olgan yangi obâektni qaytaradi.
Qaytaruvchi xotira tuzilishi:
Hozirgi vaqtda barcha obâektlarga erishish mumkin.
Endi ikkita havolani olib tashlaymiz:
delete family.father;
delete family.mother.husband;
Ushbu ikkita havoladan faqat bittasini oâchirish kifoya emas, chunki barcha obâektlarga ulanish imkoniyati mavjud.
Ammo ikkalasini ham oâchirib tashlasak, John-da boshqa hech qanday maâlumot yoâqligini koârishimiz mumkin:
Outgoing references do not matter. Only incoming ones can make an object reachable. So, John is now unreachable and will be removed from the memory with all its data that also became unaccessible. Chiqish havolalari muhim emas. Faqat kirish havolalari obâektni erishuvchan qilishi mumkin. John endi eruvchan emas va xotiradan erishish mumkin boâlmagan barcha maâlumotlar bilan olib tashlanadi.
Axlat yigâilgandan keyin:
Erishish mumkin boâlmaydigan orol
Oâzaro bogâliq obâektlarning butun âorollariâ erishish boâlmasligi va xotiradan oâchirilishi mumkin boâlgan vaziyatlar mavjud.
Manba obâekti yuqoridagi bilan bir xil. Keyin:
family = null;
Xotiraning rasmi shunday boâladi:
Ushbu misol, erishishning imkoniyati tushunchasi qanchalik muhimligini koârsatadi.
Jon va Enn hanuzgacha bir-biriga bogâlanganligi aniq, ikkalasida ham kirish havolalari mavjud. Ammo bu yetarli emas.
Avvalgi "family" obâekti ildizdan ajratib qoâyilgan, endi unga havola yoâq, shuning uchun butun orolga ulanish imkonsiz boâlib qoladi va olib tashlanadi.
Ichki algoritmlar
Axlat yigâishning asosiy algoritmi âbelgilash algoritmiâ (âmark-and-sweepâ) deb nomlanadi.
Quyidagi âaxlat yigâishâ bosqichlari muntazam ravishda amalga oshiriladi:
- Axlat yigâuvchi ildizni oladi va ularni âbelgilaydiâ (eslaydi).
- Keyin u tashrif buyuradi va ulardan barcha murojaatlarni âbelgilaydiâ.
- Keyin u belgilangan obâektlarga tashrif buyuradi va ularning havolalarini belgilaydi. Kelajakda bitta obâektga ikki marta bormaslik uchun barcha tashrif buyurgan obâektlar eslab qolinadi.
- âŠVa shunga oâxshash barcha yoânalishlarga (ildizlardan erishish mumkin) tashrif buyurilgunga qadar.
- Belgilanganlardan tashqari barcha obâektlar oâchiriladi.
Masalan, bizning obâektimiz tuzilishi quyidagi koârinishga ega boâlsin:
Biz oâng tomonga âerishib boâlmaydigan orolâ ni aniq koârishimiz mumkin. Keling, axlat yigâuvchilar u bilan qanday kurashayotganini koârib chiqaylik.
Birinchi qadam ildizlarni belgilaydi:
Keyin ularning havolalari belgilanadi:
âŠVa ularning havolalari, iloji boâlsa:
Endi jarayonda tashrif buyurib boâlmaydigan obâektlar erishish mumkin emas deb hisoblanadi va oâchirib tashlanadi:
Bu axlat yigâish qanday ishlashining kontseptsiyasi.
JavaScript interpretatori uni tezroq ishlashi va bajarilishiga taâsir qilmasligi uchun koâplab optimallashtirishlarni qoâllaydi.
Baâzi optimallashtirishlar:
- Avlodlar toâplami (Generational collection) â obâektlar ikkita toâplamga boâlinadi: âyangilariâ va âeskilariâ. Koâp obâektlar paydo boâladi, oâz ishlarini bajarishadi va tezda oâlishadi, ularni majburiy tarzda tozalash mumkin. Yetarlicha uzoq vaqt omon qolganlar, âeskiâ boâlib, kamroq tekshiriladi.
- Qoâshimcha yigâish (Incremental collection) â agar obâektlar koâp boâlsa va biz birma-bir yurib, butun obâektni belgilashga harakat qilsak, bu biroz vaqt talab qilishi va bajarilishdagi kechikishlarni keltirib chiqarishi mumkin. Shunday qilib, interpretator axlat yigâilishini qismlarga ajratishga harakat qiladi. Keyin qismlar birma-bir, alohida bajariladi. Buning uchun oâzgarishlarni kuzatib borish uchun ular oârtasida qoâshimcha hisob olib borilishi kerak, ammo bizda aksariyat kechikishlar mavjud, ammo katta emas.
- Boâsh vaqtni yigâish (Idle-time collection) â ishlashga taâsirini kamaytirish uchun axlat yigâuvchi faqat protsessor uzilishlari vaqtida ishlashga harakat qiladi.
Axlat yigâish algoritmlarini optimallashtirish va turli xil usullar mavjud. Lekin bu yerda ularni qanday taâriflashni istasam ham, men bundan kechishim kerak, chunki turli JavaScript interpretatorlari turli usullar va sozlamalardan foydalanadilar. Va bundan ham muhimi, interpretatorlarning rivojlanishi bilan hamma narsa oâzgaradi, shuning uchun bu mavzuni oldindan koârib chiqish, haqiqiy ehtiyojsiz, ehtimol bunga loyiq emas. Agar, albatta, bu sof qiziqish masalasi boâlmasa, unda quyidagi baâzi havolalar siz uchun foydali boâladi.
Xulosa
Bilish kerak boâlgan asosiy narsalar:
- Axlat yigâish avtomatik ravishda amalga oshiriladi. Biz uni majbuan oldini ololmaymiz.
- Obâektlar erishuvchan boâlganda xotirada saqlanadi.
- Yoânaltiriladigan havola (ildizdan) erishish bilan bir xil emas: oâzaro bogâlangan obâektlar toâplami umuman olganda yetib boâlmaydigan boâlib qolishi mumkin.
Zamonaviy interpretatorlar axlat yigâishning zamonaviy algoritmlarini amalga oshirmoqdalar.
Umumiy kitob âThe Garbage Collection Handbook: The Art of Automatic Memory Managementâ (R. Jons va boshqalar) ularning ayrimlarini qamrab oladi.
Agar siz past darajadagi dasturlarni yaxshi bilsangiz, V8 axlatni yigâuvchi haqida batafsil maâlumot V8 tur: Axlat yigâish maqolasida keltirilgan.
Bundan tashqari, V8 interpretatorning blogida vaqti bilan xotira boshqaruvidagi oâzgarishlar haqida maqolalar chop etiladi. Albatta, axlat yigâishni oârganish uchun siz V8 interpretatori ichida qanday ishlashini tushunishingiz kerak. Buni V8-ni ishlab chiqqan muhandislardan biri Vyacheslav Egorov blogida oâqishingiz mumkin. Men âV8â haqida gapiryapman, chunki u internetdagi maqolalar bilan eng yaxshi yoritilgan. Boshqa interpretatorda koâplab yondashuvlar oâxshash, ammo axlat yigâish koâp jihatda farq qiladi.
Interpretatorni chuqur bilish, past darajadagi optimallashtirish kerak boâlganda yaxshi boâladi. Buni til bilan tanishganingizdan keyin keyingi qadam sifatida rejalashtirish oqilona boâladi.
Izohlar
<code>yorlig'ini ishlating, bir nechta satrlar uchun - ularni<pre>yorlig'i bilan o'rab qo'ying, 10 satrdan ortiq bo'lsa - sandbox (plnkr, jsbin, codepenâŠ)