Python xotirani boshqarishga chuqur kirish, xotira havzasi arxitekturasiga va uning ishlashini yaxshilash uchun kichik ob'ektlarni ajratishni optimallashtirishdagi rolini o'rganish.
Python xotira havzasi arxitekturasi: Kichik ob'ektlarni ajratishni optimallashtirish
Ishlatish qulayligi va ko'p qirraliligi bilan tanilgan Python resurslardan samarali foydalanishni ta'minlash uchun murakkab xotirani boshqarish usullariga tayanadi. Ushbu tizimning asosiy komponentlaridan biri bu xotira havzasi arxitekturasi bo'lib, u kichik ob'ektlarni ajratish va bo'shatishni optimallashtirish uchun maxsus ishlab chiqilgan. Ushbu maqola Python xotira havzasining ichki ishlariga kirib, uning tuzilishi, mexanizmlari va ta'minlaydigan ishlash afzalliklarini o'rganadi.
Python-da xotirani boshqarishni tushunish
Xotira havzasining o'ziga xos xususiyatlariga sho'ng'ishdan oldin, Python-da xotirani boshqarishning kengroq kontekstini tushunish juda muhimdir. Python xotirani avtomatik ravishda boshqarish uchun murojaatlarni hisoblash va chiqindi yig'uvchini birlashtiradi. Murojaatlarni hisoblash ob'ektning murojaatlar soni nolga tushganda ob'ektni darhol bo'shatishni amalga oshirsa, chiqindi yig'uvchi yolg'iz murojaatlarni hisoblash hal qila olmaydigan siklik murojaatlar bilan shug'ullanadi.
Python xotirani boshqarish asosan CPython implementatsiyasi tomonidan amalga oshiriladi, bu tilning eng ko'p ishlatiladigan implementatsiyasi hisoblanadi. CPython xotira ajratuvchisi Python ob'ektlariga kerak bo'lganda xotira bloklarini ajratish va bo'shatish uchun javobgardir.
Murojaatlarni hisoblash
Python-dagi har bir ob'ektda ushbu ob'ektga murojaatlar sonini kuzatuvchi murojaatlar hisoblagichi mavjud. Murojaatlar hisoblagichi nolga tushganda, ob'ekt darhol bo'shatiladi. Ushbu darhol bo'shatish murojaatlarni hisoblashning muhim afzalligi hisoblanadi.
Misol:
import sys
a = [1, 2, 3]
print(sys.getrefcount(a)) # Natija: 2 ('a' dan biri va getrefcountning o'zidan biri)
b = a
print(sys.getrefcount(a)) # Natija: 3
del a
print(sys.getrefcount(b)) # Natija: 2
del b
# Ob'ekt hozir murojaatlar hisoblagichi 0 bo'lgani uchun bo'shatilgan
Chiqindi yig'ish
Murojaatlarni hisoblash ko'plab ob'ektlar uchun samarali bo'lsa-da, u siklik murojaatlarni hal qila olmaydi. Siklik murojaatlar ikki yoki undan ortiq ob'ektlar bir-biriga murojaat qilganda sodir bo'ladi va ularning murojaatlar hisoblagichlari hech qachon nolga yetishiga to'sqinlik qiladigan siklni yaratadi, hatto ular dasturdan endi foydalanish mumkin bo'lmasa ham.
Python chiqindi yig'uvchisi vaqti-vaqti bilan ob'ekt grafigini bunday sikllar uchun skanerlaydi va ularni buzadi, bu esa foydalanib bo'lmaydigan ob'ektlarni bo'shatishga imkon beradi. Bu jarayon dasturning global doirasidan bevosita foydalanish mumkin bo'lgan ildiz ob'ektlaridan (ob'ektlar) murojaatlarni kuzatib, foydalanib bo'lmaydigan ob'ektlarni aniqlashni o'z ichiga oladi.
Misol:
import gc
class Node:
def __init__(self):
self.next = None
a = Node()
b = Node()
a.next = b
b.next = a # Siklik murojaat
del a
del b # Ob'ektlar hali ham xotirada siklik murojaat tufayli
gc.collect() # Chiqindi yig'ishni qo'lda ishga tushirish
Xotira havzasi arxitekturasiga bo'lgan ehtiyoj
Standart xotira ajratuvchilar, masalan, operatsion tizim tomonidan taqdim etilganlar (masalan, C da malloc), umumiy maqsadli va turli o'lchamdagi ajratishlarni samarali bajarish uchun mo'ljallangan. Biroq, Python ko'plab kichik ob'ektlarni tez-tez yaratadi va yo'q qiladi, masalan, butun sonlar, satrlar va kortejlar. Ushbu kichik ob'ektlar uchun umumiy maqsadli ajratuvchidan foydalanish bir qator muammolarga olib kelishi mumkin:
- Ishlash xarajatlari: Umumiy maqsadli ajratuvchilar ko'pincha metadata boshqaruvi, qulflash va bo'sh bloklarni qidirish nuqtai nazaridan sezilarli xarajatlarni o'z ichiga oladi. Ushbu xarajat Python-da juda tez-tez uchraydigan kichik ob'ektlarni ajratish uchun sezilarli bo'lishi mumkin.
- Xotira fragmentatsiyasi: Turli o'lchamdagi xotira bloklarini takroriy ajratish va bo'shatish xotira fragmentatsiyasiga olib kelishi mumkin. Fragmentatsiya xotiraning kichik, ishlatib bo'lmaydigan bloklari butun uyum bo'ylab tarqalib ketganda sodir bo'ladi, bu esa katta ajratishlar uchun mavjud bo'lgan uzluksiz xotira miqdorini kamaytiradi.
- Kesh o'tkazib yuborishlari: Umumiy maqsadli ajratuvchi tomonidan ajratilgan ob'ektlar xotira bo'ylab tarqalib ketishi mumkin, bu esa tegishli ob'ektlarga kirishda kesh o'tkazib yuborishlarini oshiradi. Kesh o'tkazib yuborishlari protsessor tezroq kesh o'rniga asosiy xotiradan ma'lumotlarni olishi kerak bo'lganda sodir bo'ladi, bu esa ijroni sezilarli darajada sekinlashtiradi.
Ushbu muammolarni hal qilish uchun Python kichik ob'ektlarni samarali ajratish uchun optimallashtirilgan maxsus xotira havzasi arxitekturasini amalga oshiradi. Ushbu arxitektura pymalloc sifatida tanilgan, ajratish xarajatlarini sezilarli darajada kamaytiradi, xotira fragmentatsiyasini minimallashtiradi va kesh lokalitesini yaxshilaydi.
Pymalloc bilan tanishuv: Python xotira havzasi ajratuvchisi
Pymalloc - bu Python-ning kichik ob'ektlar uchun mo'ljallangan xotira ajratuvchisi, odatda 512 baytdan kichik. Bu CPython xotirani boshqarish tizimining asosiy komponenti bo'lib, Python dasturlarining ishlashida muhim rol o'ynaydi. Pymalloc katta xotira bloklarini oldindan ajratish va keyin bu bloklarni kichikroq, qattiq o'lchamdagi xotira havzalariga bo'lish orqali ishlaydi.
Pymallocning asosiy komponentlari
Pymalloc arxitekturasi bir nechta asosiy komponentlardan iborat:
- Arenalar: Arenalar Pymalloc tomonidan boshqariladigan xotiraning eng katta birliklari hisoblanadi. Har bir arena uzluksiz xotira bloki bo'lib, odatda 256 KB o'lchamda bo'ladi. Arenalar operatsion tizimning xotira ajratuvchisi yordamida ajratiladi (masalan,
malloc). - Havzalar: Har bir arena havzalar to'plamiga bo'linadi. Havza - bu kichikroq xotira bloki, odatda 4KB (bitta sahifa) o'lchamda bo'ladi. Havzalar, o'z navbatida, ma'lum bir o'lchamdagi bloklarga bo'linadi.
- Bloklar: Bloklar Pymalloc tomonidan ajratilgan xotiraning eng kichik birliklari hisoblanadi. Har bir havzada bir xil o'lchamdagi bloklar mavjud. O'lchamlar sinfi 8 baytdan 512 baytgacha, 8 baytdan ortiq qadamlarda o'zgaradi.
Diagramma:
Arena (256KB)
└── Havzalar (har biri 4KB)
└── Bloklar (8 baytdan 512 baytgacha, havza ichida bir xil o'lchamda)
Pymalloc qanday ishlaydi
Python kichik ob'ekt (512 baytdan kichik) uchun xotira ajratishi kerak bo'lganda, u avval tegishli o'lchamdagi havzada bepul blok mavjudligini tekshiradi. Agar bepul blok topilsa, u qo'ng'iroq qiluvchiga qaytariladi. Agar joriy havzada bepul blok bo'lmasa, Pymalloc bir xil arenada talab qilinadigan o'lchamdagi bepul bloklarga ega bo'lgan boshqa havza mavjudligini tekshiradi. Agar shunday bo'lsa, u holda blok shu havzadan olinadi.
Agar hech qanday mavjud havzada bepul bloklar mavjud bo'lmasa, Pymalloc joriy arenada yangi havza yaratishga harakat qiladi. Agar arenada yetarli joy bo'lsa, yangi havza yaratiladi va talab qilinadigan o'lchamdagi bloklarga bo'linadi. Agar arena to'la bo'lsa, Pymalloc operatsion tizimdan yangi arena ajratadi va jarayonni takrorlaydi.
Ob'ekt bo'shatilganda, uning xotira bloki u ajratilgan havzaga qaytariladi. Keyin blok bepul deb belgilanadi va bir xil o'lchamdagi ob'ektlarni keyinchalik ajratish uchun qayta ishlatilishi mumkin.
O'lchamlar sinflari va ajratish strategiyasi
Pymalloc ob'ektlarni o'lchamiga qarab tasniflash uchun oldindan belgilangan o'lchamlar to'plamidan foydalanadi. O'lchamlar sinfi 8 baytdan 512 baytgacha, 8 baytdan ortiq qadamlarda o'zgaradi. Bu degani, 1 dan 8 baytgacha bo'lgan ob'ektlar 8 baytli o'lcham sinfidan ajratiladi, 9 dan 16 baytgacha bo'lgan ob'ektlar 16 baytli o'lcham sinfidan ajratiladi va hokazo.
Ob'ekt uchun xotira ajratishda Pymalloc ob'ekt o'lchamini eng yaqin o'lcham sinfigacha yaxlitlaydi. Bu berilgan havzadan ajratilgan barcha ob'ektlar bir xil o'lchamda bo'lishini ta'minlaydi, bu esa xotirani boshqarishni soddalashtiradi va fragmentatsiyani kamaytiradi.
Misol:
Agar Python satr uchun 10 bayt ajratishi kerak bo'lsa, Pymalloc 16 baytli o'lcham sinfidan blok ajratadi. Qo'shimcha 6 bayt isrof qilinadi, ammo bu xarajat odatda xotira havzasi arxitekturasining afzalliklariga nisbatan kichikdir.
Pymallocning afzalliklari
Pymalloc umumiy maqsadli xotira ajratuvchilariga nisbatan bir nechta muhim afzalliklarni taklif etadi:
- Kamaytirilgan ajratish xarajatlari: Pymalloc xotirani katta bloklarda oldindan ajratish va bu bloklarni qattiq o'lchamdagi havzalarga bo'lish orqali ajratish xarajatlarini kamaytiradi. Bu operatsion tizimning xotira ajratuvchisiga tez-tez qo'ng'iroq qilish zaruratini yo'q qiladi, bu sekin bo'lishi mumkin.
- Minimallashtirilgan xotira fragmentatsiyasi: Bir xil havzadan o'xshash o'lchamdagi ob'ektlarni ajratish orqali Pymalloc xotira fragmentatsiyasini minimallashtiradi. Bu katta ajratishlar uchun uzluksiz xotira bloklari mavjudligini ta'minlashga yordam beradi.
- Yaxshilangan kesh lokalitesi: Bir xil havzadan ajratilgan ob'ektlar xotirada bir-biriga yaqin joylashgan bo'lishi mumkin, bu esa kesh lokalitesini yaxshilaydi. Bu kesh o'tkazib yuborishlari sonini kamaytiradi va dastur ijrosini tezlashtiradi.
- Tezroq bo'shatish: Ob'ektlarni bo'shatish ham Pymalloc bilan tezroq, chunki xotira bloki murakkab xotirani boshqarish operatsiyalarini talab qilmasdan shunchaki havzaga qaytariladi.
Pymalloc va tizim ajratuvchisi: Ishlashni taqqoslash
Pymallocning ishlash afzalliklarini ko'rsatish uchun Python dasturi ko'p sonli kichik satrlarni yaratadigan va yo'q qiladigan ssenariyni ko'rib chiqing. Pymallocsiz har bir satr operatsion tizimning xotira ajratuvchisi yordamida ajratiladi va bo'shatiladi. Pymalloc bilan satrlar oldindan ajratilgan xotira havzalaridan ajratiladi, bu ajratish va bo'shatish xarajatlarini kamaytiradi.Misol:
import time
def allocate_and_deallocate(n):
start_time = time.time()
for _ in range(n):
s = "salom"
del s
end_time = time.time()
return end_time - start_time
n = 1000000
time_taken = allocate_and_deallocate(n)
print(f"{n} ta satrni ajratish va bo'shatish uchun ketgan vaqt: {time_taken:.4f} sekund")
Umuman olganda, Pymalloc ko'p sonli kichik ob'ektlarni ajratadigan va bo'shatadigan Python dasturlarining ishlashini sezilarli darajada yaxshilashi mumkin. Aniq ishlash o'sishi maxsus ish yukiga va operatsion tizimning xotira ajratuvchisining xususiyatlariga bog'liq bo'ladi.
Pymallocni o'chirish
Pymalloc odatda ishlashni yaxshilasa-da, u muammolarga olib kelishi mumkin bo'lgan vaziyatlar bo'lishi mumkin. Misol uchun, ba'zi hollarda Pymalloc tizim ajratuvchisiga nisbatan xotiradan foydalanishni oshishiga olib kelishi mumkin. Agar siz Pymalloc muammolarga olib kelmoqda deb gumon qilsangiz, PYTHONMALLOC muhit o'zgaruvchisini default ga o'rnatish orqali uni o'chirib qo'yishingiz mumkin.
Misol:
export PYTHONMALLOC=default #Pymallocni o'chiradi
Pymalloc o'chirilganda, Python barcha xotira ajratishlari uchun operatsion tizimning standart xotira ajratuvchisidan foydalanadi. Pymallocni o'chirish ehtiyotkorlik bilan amalga oshirilishi kerak, chunki u ko'p hollarda ishlashga salbiy ta'sir ko'rsatishi mumkin. Ilovangizni Pymalloc bilan va usiz optimal konfiguratsiyani aniqlash uchun profilingizni o'tkazish tavsiya etiladi.
Turli Python versiyalarida Pymalloc
Pymallocning implementatsiyasi Pythonning turli versiyalari bo'ylab rivojlangan. Ilgari versiyalarda Pymalloc C da amalga oshirilgan. Keyingi versiyalarda implementatsiya ishlashni yaxshilash va xotiradan foydalanishni kamaytirish uchun takomillashtirilgan va optimallashtirilgan.Xususan, Pymalloc bilan bog'liq xatti-harakatlar va konfiguratsiya parametrlari Python 2.x va Python 3.x o'rtasida farq qilishi mumkin. Python 3.x da Pymalloc odatda yanada mustahkam va samaralidir.
Pymallocga alternativalar
Pymalloc CPython-da kichik ob'ektlar uchun standart xotira ajratuvchisi bo'lsa-da, buning o'rniga ishlatilishi mumkin bo'lgan muqobil xotira ajratuvchilari mavjud. Mashhurligi va kengayishi bilan tanilgan jemalloc ajratuvchisi mashhur alternativlardan biridir.
Python bilan jemallocdan foydalanish uchun siz uni tuzish vaqtida Python interpretatori bilan bog'lashingiz kerak. Bu odatda tegishli bog'lovchi bayroqlari bilan Pythonni manbadan qurishni o'z ichiga oladi.
Eslatma: Jemalloc kabi muqobil xotira ajratuvchidan foydalanish sezilarli ishlash yaxshilanishini ta'minlashi mumkin, ammo uni o'rnatish va sozlash ham ko'proq harakat talab qiladi.
Xulosa
Python xotira havzasi arxitekturasi, Pymalloc uning asosiy komponenti sifatida, kichik ob'ektlarni ajratishni samarali boshqarish orqali Python dasturlarining ishlashini sezilarli darajada yaxshilaydigan muhim optimallashtirishdir. Xotirani oldindan ajratish, fragmentatsiyani minimallashtirish va kesh lokalitesini yaxshilash orqali Pymalloc ajratish xarajatlarini kamaytirishga va dastur ijrosini tezlashtirishga yordam beradi.
Pymallocning ichki ishlarini tushunish sizga yanada samarali Python kodini yozishga va xotira bilan bog'liq ishlash muammolarini bartaraf etishga yordam beradi. Pymalloc odatda foydali bo'lsa-da, uning cheklovlaridan xabardor bo'lish va agar kerak bo'lsa, muqobil xotira ajratuvchilarini ko'rib chiqish muhimdir.
Python rivojlanishda davom etar ekan, uning xotirani boshqarish tizimi, ehtimol, yanada takomillashtirish va optimallashtirishlarga duch keladi. Ushbu o'zgarishlardan xabardor bo'lish o'z ilovalarining ishlashini maksimal darajada oshirishni istagan Python dasturchilari uchun zarurdir.
Qo'shimcha o'qish va resurslar
- Xotirani boshqarish bo'yicha Python hujjatlari: https://docs.python.org/3/c-api/memory.html
- CPython manba kodi (Objects/obmalloc.c): Ushbu faylda Pymalloc implementatsiyasi mavjud.
- Python xotirani boshqarish va optimallashtirish bo'yicha maqolalar va blog postlari.
Ushbu tushunchalarni tushunib, Python dasturchilari xotirani boshqarish bo'yicha asosli qarorlar qabul qilishlari va keng ko'lamli ilovalarda samarali ishlaydigan kod yozishlari mumkin.