Python Garbage Collector

Xotira boshqaruvi

Dasturlash tillar malumotlar ustida operatsiya bajarish uchun obyektlardan foydalanishadi. Obyektlar sonlar bo'lishi mumkin, matnlar bo'lishi mumkin, yoki mantiqiy malumotlar. Bazida obyektlar komplex malumot turlari ham bo'lishi mumkin, list, hash yoki class kabi.

Dasturlarda obyektlardan unumli foydalanish uchun ularni xotiraga saqlab qo'yadilar va kerak bo'lganda xotiradan olib ishlatadilar. Bazi dasturlash tillarida o'zgaruvchilar aslida xotirada saqlangan obyektga shunchaki havola bo'ladi.

Birinchi dasturlash tillarida xotira boshqaruvi uchun dasturchi to'liq javobgar bo'lgan, agar u biror obyekt yaratmoqchi bo'lsa uning uchun avval xotiradan joy ajratgan, obyektni ishlatib bo'lgandan so'ng esa xotirani bo'shatib qo'yishi kerak bo'lgan.

Bu yerda ikkita muammo bor:

  1. Xotirani bo'shatib qo'yish esadan chiqib qolishi. Xotirani ishlatib bo'lgandan keyin uni bo'shatishni unutib qo'yaverish xotirani to'lib qolishiga olib keladi.
  2. Xotirani erta bo'shatib qo'yish. Ikkinchi muammo esa xotira hali foydalanilayotgan vaqtda uni bo'shatib yuborish.

Avtomatik xotira boshqaruvi va axlat yig'uvchi (garbage collector)

Avtomatik xotira boshqaruvi uchun turli xil metodlardan foydalaniladi. Eng keng tarqalgan boshqaruv usullaridan biri bu reference counting. Dastur obyketlarning referencelarini doim kuzatib boradi, reference counti 0 ga teng bo'lga obyket ishlatilmayotgan hisoblanadi va u band qilib turgan xotira ozod qilinadi.

Ammo avtomatik xotira boshqaruvi biroz qimmatga tushadi, sababi buning uchun qo'shimcha xotira va qo'shimcha hisob kitob kerak bo'ladi. Ko'plab dasturlash tillarida "stop-the-world" metodikasi ishlaydi, bunda garbage collector ishlatilmayotgan obyektlarni collect qilayotgan vaqtda boshqa hama narsa to'xtatiladi.

Kompyuter olami Moor qonunida aytilgani kabi rivojlanib yangi kompyuterlarda katta miqdordagi RAM lar sabab,  avtomatik xotira boshqaruvining kamchiliklari ortib borayapti. Shunga qaramay zamonaviy dasturlash tillari Golang, Java va Python kabi dasturlash tillarida avtomatik xotira boshqaruvi mavjud.

Uzoq ishlovchi va tezlik o'ta muhim bo'lgan dasturlarda ishlatilgadigan dasturlash tillarida hali ham manula xotira boshqaruvi ishlatiladi. Klassik misol C++. Yana MacOS va IOS uchun ishlatiladigan objective-C, va yangi dasturlash tillaridan Rust ni misol qilishimiz mumkin.

Pythonda garbage collection qanday ishlaydi

Pythonda xotira boshqaruvida ikkita aspekt mavjud:

  1. Recerence counting
  2. Generational garbage collection

Reference counting

Pythonda garbage collectionning asosiy quroli bu reference countlar. Pythonda biz doim obyekt yaratganimizda, yaratilgan obyektning ikkita havolasi bo'ladi, birinchisi C type - list, dictionary, yoki int ga o'xshaga, ikkinchisi reference count.

Bazilar python garbage collectorni "poor man's garbage collector"i deb nomlashadi. Sababi u davriy reference larni aniqlay olmaydi. Ammo reference countingning bir joyib tomoni u xotiraga hechkim murojaat qilmasa u xotirani bo'shatib qo'yadi.

Generational garbage collection

Reference countga qo'shimcha tarzda Python garbage collector metodini ham xotira boshqaruvi uchun ishlatadi.

Avalgi bo'limda biz obyektni arrayga qo'shib uning reference counti ishganini ko'rdik. Ammo obyekti uning o'ziga qo'shsak nima bo'ladi.

>>> class MyClass(object):
...     pass
...
>>> a = MyClass()
>>> a.obj = a
>>> del a

Ushbu misolda biz class yasadik va shu classga instance yasadik, va shu instance ning proertysi sifatida o'zini ko'rsatdik. Xullas instanceni o'chirib tashladik.

Endi Python uchun ushbu instance mavhum, lekin uni Python xotiradan o'chirib tashlamadi. Instancening reference counti 0 emas, sababi uning o'ziga o'zi reference qilingan edi.

Ushbu muammo reference sikli deyiladi, biz bu muammoni reference count bilan hal qila olmaymiz. Ushbu muammoni hal qilish garbage collectorning ishi, standard bibliotekada u GC nomi ostida.

Generational garbage collection terminology

Garbage collectorni tushunish uchun ikkita muhim konsepsiya mavjud:

  1. birinchi konsepsiya avlod (level, type).
  2. ikkinchisi esa chegara.

Garbage collector xotiradagi barcha obyektarni kuzatib boradi. Yangi yaratilgan obyekt garbage collectorning birinchi avlodida yashashni boshlaydi. Agar Python garbage collectionni boshlasa va unda obyket saqlanib qolsa u ikkinchi avlodga o'tib yashashni boshlaydi. Pythonda garbage collectorning umumiy uchta avlodi bor, har bir ovlod bo'yicha garbage collect qilinganda saqlanib qolgan obyektlar o'zidan keyingi avoldga o'tib yashashni davom ettirishadi.

Har bir avlod uchun garbage collector modulining chegaralangan miqdorda obyektlar soni mavjud. Agar biror avlodda obyektlar soni belgilangandan oshib ketsa garbage collection jarayoni boshlanadi. Istalgan garbage collectiondan omon qolgan obyketlar o'zi turgan avolddan keyingi avlodga o'tib yashashda davom etadilar.

Reference countdan farqli o'laroq, siz garbage collectorni boshqarishingiz mumkin. Misol uchun obyektlar soni chegarasini o'zgartirish. Yoki garbage collection jarayonini o'zingiz boshlashingiz yoki garbage collect qilishni umuman to'xtatib qo'yishingiz ham mumkin.

GC moduldan foydalanish

gc modulini import qiling va python uchun hozirda belgilangan garbage collector chegarasini ko'ring:

>>> import gc
>>> gc.get_threshold()
(700, 10, 10)

Demak o'z o'rnida, birinchi avlod uchun 700 ta obyekt, va keyingi ikkita avlod uchun esa 10 tadan obyekt uchun ruxsat berilgan ekan.

get_count() orqali siz har bir avlodda nechtadan obyekt yashayotganini ham ko'rishingiz mumkin:

>>> import gc
>>> gc.get_count()
(596, 2, 1)

Ushbu holatda sizda eng yosh avlodingizda 596 ta ikkinchi avlodda esa 2 ta va uchinchi avlodda 1 ta obyket bor.

Ko'rib turganingizdek Python hali dasturni yozmasingizdan yoki ishga tushirmasingizdan o'zi bir olam obyket yaratib ulguradi. Biz garbage collection jarayonini o'zimiz ham gc.collect() funksiyasi orqali ishga tushira olamiz.

>>> gc.get_count()
(595, 2, 1)
>>> gc.collect()
577
>>> gc.get_count()
(18, 0, 0)

Ko'rib turganingizdek collect() funksiyasi katta miqdorda obyektlarni tozalab tashlaydi. Bu xolatda u naqd 577 ta obyektdan xotirani tozaladi.

Biz set_threshold() funksiyasi orqali avlodlarda saqlanadigan obyketlar soni o'zimiz o'rnatishimiz mumkin.

>>> import gc
>>> gc.get_threshold()
(700, 10, 10)
>>> gc.set_threshold(1000, 15, 15)
>>> gc.get_threshold()
(1000, 15, 15)

Yuqoridagi misolda biz garbage collection chegaraladini o'zimiz o'rnatdik. Ushbu chegaralarni uzaytirish garbage collection ishga tushish vaqtini uzaytiradi, va o'lik obyektlarni xotirada uzoqroq saqlab turishi evaziga dasturingizda yuz beradigan hisob kitoblarni kamaytiradi.

Python dasturchi sifatida siz uchun garbage collector nima mano anglatadi ?

Garbage collectoring asl konfiguratsiyasini o'zgartirmang. Asosiy jihatlardan biri Python dasturchining foydali ish koeffetsentini sezilarli oshiradi. Va albatta bu low level dasturlash tillarida dasturchi qilishi kerak bo'lga mayda ishlarni Python o'z bo'yniga olishidir.

Zich muhitlar uchun xotirani manual boshqarish muhim bo'lishi mumkin. Bu bilimlar bilan endi siz bazida sizning dasturingiz unumdorligi pastligini garbage collectionga to'nkashingiz ham odatiy xol, lekin ishonavering shunday xolatda ham garbage collector chegaralarini kengaytirgandan ko'ra dasturingiz ishlab turgan muhitni kuchaytirganingiz foydaliroq. Moore ning qoidasi aytganidek hozirda bizga kerakli kuchga ega mexanizmlarni arzonga topish hozirgi kunda oson.

Python o'zi ozod qilgan xotirani o'zi ishlab turgan OS ga qaytarmasligi aniq. Shu sababli istalgan manual garbage collection sizga o'zingiz kutgan natijani bermasligi mumkin.