Yakunlovchi - Finalizer

Yilda Kompyuter fanlari, a yakunlovchi yoki yakuniy usul maxsus usul bajaradigan yakunlash, odatda tozalashning bir turi. Finalist amalga oshirilmoqda ob'ektni yo'q qilish, ob'ekt mavjud bo'lishidan oldin ajratilgan va an-ni to'ldiradi boshlovchi davomida bajariladigan ob'ektni yaratish, quyidagi ajratish. To'g'ri ishlatishda qiyinchiliklar va ular qo'shadigan murakkablik tufayli finalistlar ba'zilari tomonidan qattiq tushkunlikka tushadi va buning o'rniga muqobil variantlar taklif etiladi, birinchi navbatda naqshni yo'q qilish[1] - qarang finalizatorlar bilan bog'liq muammolar.

"Finalizer" atamasi birinchi navbatda ishlatiladi ob'ektga yo'naltirilgan va funktsional tillar foydalanish axlat yig'ish, ulardan arxetipi Kichik munozarasi. Bunga "halokatchi ", bu metod arxetipik ravishda aniqlanadigan ob'ektning umr ko'rish muddati bo'lgan tillarda yakunlashga chaqiriladi C ++.[2][3] Ular odatda eksklyuzivdir - tilda finalistlar (avtomatik ravishda axlat yig'ilsa) yoki destruktorlar (agar qo'lda xotira boshqarilsa) bo'ladi, lekin kamdan-kam hollarda tilda ikkalasi ham bo'lishi mumkin, C ++ / CLI va D. va agar bo'lsa ma'lumotni hisoblash (axlatni yig'ish o'rniga), atamalar har xil. Texnik foydalanishda "finalizer" dan destruktorlarga murojaat qilish uchun ham foydalanish mumkin, chunki ular yakuniy natijani bajaradi va ba'zi bir nozik farqlar mavjud - qarang atamashunoslik. "Final" atamasi, mumkin bo'lmagan sinfni ko'rsatish uchun ham ishlatiladi meros qilib olingan; bu bog'liq emas.

Terminologiya

"Yakunlovchi" va "yakunlovchi" va "halokat" va "yo'q qilish" terminologiyasi mualliflar o'rtasida turlicha bo'lib, ba'zida tushunarsiz bo'ladi.

Umumiy foydalanishda, a halokatchi ob'ektni yo'q qilishda deterministik deb nomlangan usul bo'lib, arxetip - C ++ destruktorlari; finalist esa axlat yig'uvchi tomonidan deterministik bo'lmagan deb nomlanadi va arxetip Java yakunlash usullari.

Orqali axlat yig'ishni amalga oshiradigan tillar uchun ma'lumotni hisoblash kabi ba'zi tillarda terminologiya turlicha Maqsad-C va Perl "destructor" dan foydalanadi va "finalizer" dan foydalanadigan Python kabi boshqa tillar (har bir spetsifikatsiya bo'yicha Python axlat yig'iladi, lekin mos yozuvlar CPython uning 2.0 versiyasida mos yozuvlar sanash va axlat yig'ish kombinatsiyasidan foydalanilganligi sababli amalga oshiriladi). Bu mos yozuvlar sanash natijasida ob'ektning ishlash muddati yarim-deterministik bo'lishiga olib keladi: tsikl tarkibiga kirmaydigan ob'ektlar uchun mos yozuvlar soni nolga tushganda ob'ektlar deterministik tarzda yo'q qilinadi, ammo tsikl tarkibiga kiradigan ob'ektlar noaniq-deterministik tarzda yo'q qilinadi , axlat yig'ishning alohida shaklining bir qismi sifatida.

Muayyan tor texnik foydalanishda "konstruktor" va "destruktor" til darajasidagi atamalar bo'lib, "sinfda aniqlangan usullar" degan ma'noni anglatadi, "boshlang'ich" va "yakunlovchi" - bu ob'ektlarni yaratish paytida chaqirilgan usullar yoki yo'q qilish ". Masalan, C # tili uchun xos spetsifikatsiya "destruktorlar" deb nomlanadi, garchi C # axlat yig'ilsa ham, lekin Umumiy til infratuzilmasi (CLI) va uning ishlash vaqti muhitini Umumiy til ishlash vaqti (CLR), "finalizatorlar" deb nomlangan. Bu C # til qo'mitasining eslatmalarida aks ettirilgan bo'lib, unda qisman o'qilgan: "C # kompilyatori destruktorlarni ... [ehtimol] instansiyani yakunlovchi [lar] ga kompilyatsiya qiladi".[4][5] Ushbu atamashunoslik chalkash va shuning uchun C # specning so'nggi versiyalari til darajasidagi uslubni "yakunlovchi" deb ataydi.[6]

Ushbu terminologiyani ajratib ko'rsatmaydigan yana bir til - D. Garchi D sinflari axlat yig'ilsa ham, ularni tozalash funktsiyalari destruktorlar deb ataladi.[7]

Foydalanish

Yakunlash asosan tozalash, xotira yoki boshqa manbalarni bo'shatish uchun ishlatiladi: orqali ajratilgan xotirani ajratish uchun xotirani qo'lda boshqarish; agar mos yozuvlarni tozalash uchun ma'lumotni hisoblash ishlatiladi (kamayish bo'yicha mos yozuvlar soni); resurslarni bo'shatish, xususan Resurslarni sotib olish - bu ishga tushirish (RAII) iborasi; yoki ob'ektni ro'yxatdan chiqarish uchun. Yakuniylashtirish hajmi tillar orasida sezilarli darajada farq qiladi, C ++ da yakuniy yakunlashgacha, unda xotirani qo'lda boshqarish, mos yozuvlar bilan hisoblash va ob'ektning umr ko'rish muddati mavjud; ob'ektning umrini deterministik bo'lmagan va tez-tez kuzatuvchi axlat yig'uvchi bilan amalga oshiriladigan Java-da ko'pincha yakunlash bo'lmaydi. Bundan tashqari, aniq (foydalanuvchi tomonidan belgilangan) yakunlash juda kam yoki umuman bo'lmasligi mumkin, lekin kompilyator, tarjimon yoki ish vaqti tomonidan bajariladigan muhim yopiq yakunlash; kabi, avtomatik mos yozuvlar hisoblashda keng tarqalgan CPython Python-ning mos yozuvlar dasturi yoki Avtomatik ma'lumotni hisoblash Apple dasturida Maqsad-C, ikkalasi ham yakunlash paytida havolalarni avtomatik ravishda buzadi. Finalist o'zboshimchalik bilan kodni o'z ichiga olishi mumkin; ayniqsa murakkab foydalanish ob'ektni avtomatik ravishda an-ga qaytarishdir ob'ekt havzasi.

Yakunlash paytida xotirani taqsimlash C ++ singari tillarda tez-tez uchraydi, bu erda xotirani qo'lda boshqarish standart bo'lgan, lekin boshqariladigan tillarda xotira boshqariladigan uyadan tashqarida ajratilganda ham (til uchun tashqi); Java-da bu bilan sodir bo'ladi Java mahalliy interfeysi (JNI) va ByteBuffer ob'ektlar Yangi I / O (NIO). Bu axlat yig'uvchilar ushbu tashqi manbalarni kuzatib bo'lmaydiganligi sababli muammolarni keltirib chiqarishi mumkin, shuning uchun ular etarlicha agressiv tarzda to'planmaydi va boshqarilmaydigan xotirani charchatishi sababli xotiradan tashqarida xatolarga olib kelishi mumkin - bu mahalliyni davolash orqali oldini olish mumkin xotira manba sifatida va naqshni yo'q qilish, quyida muhokama qilinganidek.

Finalizatorlar, odatda, destruktorlarga qaraganda ancha kam va juda kam qo'llaniladi. Ular juda kam zarur, chunki axlat yig'ish avtomatlashadi xotirani boshqarish va umuman olganda kamroq ishlatiladi, chunki ular umuman deterministik tarzda ijro etilmaydi - ular o'z vaqtida chaqirilmasligi mumkin, hatto umuman bo'lmasligi mumkin va ijro etiladigan muhitni oldindan aytib bo'lmaydi - va shuning uchun deterministik usulda bajarilishi kerak bo'lgan har qanday tozalash o'rniga boshqa usul bilan amalga oshiriladi, ko'pincha qo'l bilan naqshni yo'q qilish. Ta'kidlash joizki, Java ham, Python ham finalistlar chaqirilishini kafolatlamaydi va shuning uchun ularni tozalashga ishonib bo'lmaydi.

Ularning bajarilishi ustidan dasturchilar tomonidan nazorat qilinmaganligi sababli, odatda, eng ahamiyatsiz operatsiyalar uchun yakunlovchi dasturlardan qochish tavsiya etiladi. Xususan, ko'pincha destruktorlarda bajariladigan operatsiyalar, odatda finalistlar uchun mos kelmaydi. Umumiy naqshga qarshi finalizatorlar va destruktorlar o'rtasidagi farq tufayli, keraksiz va samarasiz bo'lgan, xuddi buzuvchilardek yozuvchilarni yozishdir. Bu, ayniqsa, keng tarqalgan C ++ dasturchilar, chunki destruktorlar quyidagilardan kelib chiqib, idiomatik C ++ da juda ko'p qo'llaniladi Resurslarni sotib olish - bu ishga tushirish (RAII) iborasi.

Sintaksis

Yakunlovchi dasturlardan foydalanadigan dasturlash tillariga quyidagilar kiradi C ++ / CLI, C #, Toza, Boring, Java va Python. Sintaksis tilga qarab sezilarli darajada farq qiladi.

Java-da finalizer deb nomlangan usul yakunlash, bu bekor qiladi Ob'ekt.finalize usul.[8]

Python-da yakunlovchi - bu usul __dil__.

Perlda finalist deb nomlangan usul YO'Q.

C # da finalizer (standartning oldingi versiyalarida "destruktor" deb nomlanadi) - bu nomi nomi bilan sinf nomi bo'lgan usul. ~ kabi old qo'shimchalar ~ Foo - bu C ++ bilan bir xil sintaksis halokatchiva bu usullar dastlab turli xil xulq-atvorga ega bo'lishiga qaramay, C ++ bilan taqqoslaganda "destruktorlar" deb nomlangan, ammo sabab bo'lgan chalkashliklar tufayli "finalizatorlar" deb o'zgartirilgan.[6]

Ham destruktorlar, ham finalizatorlarga ega bo'lgan C ++ / CLI-da destruktor - bu nomi nomi bilan sinf nomi bo'lgan usul. ~ kabi old qo'shimchalar ~ Foo (C # da bo'lgani kabi) va yakunlovchi - bu sinf nomi bo'lgan usul ! kabi old qo'shimchalar ! Foo.

Go-da finalizatorlar bitta ko'rsatgichga qo'ng'iroq qilib qo'llaniladi ish vaqti.SetFinalizer standart kutubxonada ishlash.[9]

Amalga oshirish

Agar finalist bo'lsa, qachon deyiladi ob'ekt axlat yig'ilgan - ob'ekt axlatga aylanganidan keyin (erishish mumkin emas), lekin uning xotirasi taqsimlanmasdan oldin. Yakunlash jarayoni axlat yig'uvchining qaroriga binoan determinatsiz ravishda amalga oshiriladi va hech qachon yuz berishi mumkin emas. Bu ob'ekt foydalanilmay qolishi bilanoq deterministik ravishda chaqiriladigan va har doim chaqiriladigan destruktorlar bilan qarama-qarshi bo'lib, dastur nazoratsiz tugatilgan hollar bundan mustasno. Finalizatorlar ko'pincha misol usullari, ob'ektga xos operatsiyalarni bajarish zarurati tufayli.

Axlat yig'uvchi ham ob'ektni tiriltirish imkoniyatini hisobga olishi kerak. Odatda bu avval yakunlovchi dasturlarni bajarish, so'ngra biron bir ob'ekt tirilganligini tekshirish va agar yo'q qilinishini bekor qilish orqali amalga oshiriladi. Ushbu qo'shimcha tekshirish qimmatga tushishi mumkin - oddiy dastur barcha axlatlarni qayta tekshiradi, agar bitta ob'ektda ham yakunlovchi bo'lsa - va shuning uchun ham axlat yig'ilishi sekinlashadi va qiyinlashadi. Shu sababli, yakunlovchi bilan ob'ektlar tez-tez yakunlanishi mumkin bo'lmagan narsalarga qaraganda kamroq to'planishi mumkin (faqat ba'zi tsikllarda), bu tezda tugatishga tayanish natijasida yuzaga keladigan muammolarni kuchaytiradi, masalan, resurslar oqishi.

Agar ob'ekt tiriltirilsa, uning yakuniylashtiruvchisi qayta chaqiriladimi-yo'qmi degan savol tug'iladi, u keyingi yo'q qilinganida - destruktorlardan farqli o'laroq finalizatorlar bir necha bor chaqirilishi mumkin. Agar finalizatorlar tiriltirilgan narsalarga chaqirilsa, ob'ektlar o'zlarini qayta-qayta tiriltirishi va buzilmasligi mumkin; bu Python 3.4 ga qadar Pythonning CPython dasturida va C # kabi CLR tillarida uchraydi. Bunga yo'l qo'ymaslik uchun ko'plab tillarda, jumladan Java, Objective-C (hech bo'lmaganda so'nggi Apple dasturlarida) va Python 3.4-dan Python, ob'ektlar bir vaqtning o'zida yakunlanadi, bu ob'ekt hali tugatilganligini kuzatishni talab qiladi.

Boshqa holatlarda, xususan C # kabi CLR tillari, yakunlash ob'ektlarning alohida qismidan alohida kuzatiladi va ob'ektlar qayta-qayta ro'yxatdan o'tkazilishi yoki tugatish uchun ro'yxatdan o'tkazilishi mumkin.

Muammolar

Finalizatorlar ko'plab muammolarni keltirib chiqarishi mumkin va shuning uchun bir qator vakolatli organlar tomonidan qattiq tushkunlikka tushiriladi.[10][11] Ushbu muammolarga quyidagilar kiradi:[10]

  • Finalchilar o'z vaqtida yoki umuman chaqirilmasligi mumkin, shuning uchun ularga davlatni saqlab qolish, kam manbalarni chiqarish yoki boshqa muhim ishlarni bajarish uchun ishonib bo'lmaydi.
  • Yakunlovchi natijalar bo'lishi mumkin ob'ektning tirilishi, bu ko'pincha dasturiy xato bo'lib, uning imkoniyati axlat yig'ishni ancha sekinlashtiradi va murakkablashtiradi.
  • Yakuniylashtiruvchilar axlat yig'ish asosida boshqariladi, bu odatda xotiraning boshqariladigan bosimiga asoslangan - ular boshqa resurslar etishmasligi holatida ishlatilmaydi va shu sababli boshqa kam manbalarni boshqarish uchun mos emas.
  • Finalchilar belgilangan tartibda ishlamaydilar va ularga ishonishlari mumkin emas sinf invariantlari (ular allaqachon yakunlangan boshqa ob'ektlarga tegishli bo'lishi mumkin).
  • Sekin finalizatorlar boshqa finalistlarni kechiktirishi mumkin.
  • Yakuniylashtiruvchilar ichidagi istisnolarni odatda ko'rib bo'lmaydi, chunki yakunlovchi aniqlanmagan muhitda ishlaydi va e'tiborsiz qoldirilishi yoki nazoratsiz dastur bekor qilinishiga olib kelishi mumkin.
  • Yakuniylashtiruvchilar jonli ob'ektlarga murojaat qilishlari va tasodifan yakunlashlari, dasturning o'zgaruvchanligini buzishlari mumkin.
  • Finalizatorlar sinxronizatsiya muammosini keltirib chiqarishi mumkin, hattoki boshqa ketma-ketlikdagi (bitta ipli) dasturlarda ham, yakunlash bir vaqtda (aniq qilib aytganda, bir yoki bir nechta alohida satrlarda) amalga oshirilishi mumkin.[12]
  • Finalistlar belgilangan tartibda ishlamasligi va ehtimol bir vaqtda ishga tushirilishi sababli qulflar singari sinxronizatsiya mexanizmlaridan foydalanilsa, blokirovkaga olib kelishi mumkin.
  • Dasturni tugatish paytida ishlaydigan finalistlar odatdagi ish vaqti muhitiga tayanolmaydilar va shuning uchun noto'g'ri taxminlar tufayli ishlamay qolishlari mumkin - shu sababli tugatuvchilar ko'pincha tugatish paytida ishlamaydilar.

Bundan tashqari, yakunlovchi dasturlar dasturlash xatolari yoki kutilmagan kirish imkoniyati tufayli chiqindilar bo'lishi kutilgan vaqtdan tashqari mavjud bo'lgan ob'ekt tufayli ishlamay qolishi mumkin. Masalan, Python istisno holatini aniqlaganda (yoki istisno interaktiv rejimda tutilmaydi), u istisno ko'tarilgan stek ramkasiga havolani saqlaydi, bu esa ushbu stek ramkasidan havola qilingan ob'ektlarni tirik saqlaydi.

Superklassdagi finalistlar, shuningdek, subklassdagi axlat yig'ishni sekinlashtirishi mumkin, chunki finalist potentsial ravishda subklassdagi maydonlarni nazarda tutishi mumkin va shuning uchun maydon finalist ishga tushirilgandan so'ng, keyingi tsiklga qadar axlat yig'ib bo'lmaydi.[10] Buning yordamida oldini olish mumkin meros ustidan tarkibi.

Resurslarni boshqarish

Umumiy naqshga qarshi ga o'xshashlik bilan resurslarni chiqarish uchun yakunlovchi vositalardan foydalanish Resurslarni sotib olish - bu ishga tushirish (RAII) iborasi C ++: initsializatorda (konstruktorda) manbaga ega bo'ling va uni yakunlovchi (destruktor) da chiqaring. Bu bir necha sabablarga ko'ra ishlamaydi. Asosan, finalizatorlar hech qachon chaqirilmasligi mumkin va hatto chaqirilgan bo'lsa ham, o'z vaqtida chaqirilmasligi mumkin - shuning uchun resurslarni chiqarish uchun finalizatorlardan foydalanish odatda sabab bo'ladi resurs qochqinlari. Bundan tashqari, finalistlar belgilangan tartibda chaqirilmaydi, resurslar ko'pincha ma'lum bir tartibda chiqarilishi kerak, aksincha ular sotib olingan tartibda. Bundan tashqari, axlat yig'uvchilarning qaroriga binoan finalistlar chaqirilganligi sababli, ular tez-tez faqat boshqariladigan xotira bosimi ostida (boshqariladigan xotira mavjud bo'lmaganda) manba bosimidan qat'i nazar chaqiriladi - agar kam manbalar axlatga tegishli bo'lsa, lekin ko'p bo'lsa mavjud bo'lgan xotira mavjud bo'lsa, axlat yig'ib olinmasligi mumkin, shuning uchun bu resurslarni qaytarib bo'lmaydi.

Shunday qilib, axlat yig'iladigan tillarda resurslarni avtomatik boshqarish uchun yakunlovchi vositalardan foydalanish o'rniga resurslarni qo'lda boshqarish kerak, odatda naqshni yo'q qilish. Bunday holda, resurslar boshlang'ich moslamada olinishi mumkin, bu ob'ektni instantatsiya qilishda aniq deb nomlanadi, ammo yo'q qilish usulida chiqariladi. Tasdiqlash usuli aniq yoki to'g'ridan-to'g'ri C # kabi til konstruktsiyalari tomonidan chaqirilishi mumkin foydalanish, Java harakat qilib ko'ring- yoki resurslar bilan yoki Pythonniki bilan.

Biroq, ba'zi hollarda, resurslarni chiqarish uchun sarflash sxemasi va yakunlovchi vositalardan foydalaniladi. Bu, birinchi navbatda, C # kabi CLR tillarida uchraydi, bu erda tugatish utilizatsiya qilish uchun zaxira sifatida ishlatiladi: resurs olgach, oluvchi ob'ekt yakunlash uchun navbatga qo'yiladi, shunda resurs yo'q bo'lganda ham, ob'ekt ob'ektni yo'q qilishda bo'shatiladi qo'lda yo'q qilish yo'li bilan chiqarilgan.

Deterministik va determinatsion bo'lmagan ob'ektlarning ishlash muddati

Ob'ektning aniq ishlash muddati, xususan C ++ tillarida, resurslarni boshqarish tez-tez resurslarga egalik qilish muddatini ob'ektning ishlash muddatiga bog'lash, ishga tushirish paytida resurslarni sotib olish va ularni yakunlash paytida chiqarish orqali amalga oshiriladi; bu sifatida tanilgan Resurslarni sotib olish - bu ishga tushirish (RAII). Bu resurslarga egalik qilishni ta'minlaydi sinf o'zgarmas va ob'ekt yo'q qilinganida darhol resurslar chiqariladi.

Biroq, ob'ektning ishlash muddati aniq bo'lmagan (masalan, C #, Java va Python kabi axlat yig'iladigan barcha asosiy tillarni o'z ichiga olgan) tillarda bu ishlamaydi, chunki yakunlash o'z vaqtida bo'lmasligi yoki umuman bo'lmasligi mumkin va shuning uchun resurslar sabab bo'lishi mumkin, uzoq vaqt yoki hatto umuman chiqarilmasligi mumkin resurs qochqinlari. Ushbu tillarda resurslar odatda qo'l bilan boshqarish orqali amalga oshiriladi naqshni yo'q qilish: resurslar hali ham ishga tushirish paytida olinishi mumkin, ammo a qo'ng'iroqlari orqali chiqariladi yo'q qilish usul. Shunga qaramay, ushbu tillarda manbalarni chiqarish uchun yakuniy natijalardan foydalanish odatiy holdir naqshga qarshi va qo'ng'iroq qilishni unutib qo'ydi yo'q qilish hali ham resurslar oqishiga sabab bo'ladi.

Ba'zi hollarda, ikkala usul ham aniq usuldan foydalangan holda birlashtiriladi, shuningdek, zaxira sifatida yakunlash paytida hanuzgacha saqlanib qolgan resurslarni chiqaradi. Bu odatda C # -da uchraydi va resursni sotib olishda ob'ektni yakunlash uchun ro'yxatdan o'tkazish va resurs chiqarilganda tugatishni to'xtatish orqali amalga oshiriladi.

Ob'ektni qayta tiklash

Agar foydalanuvchi tomonidan belgilangan yakunlovchi qurilmalarga ruxsat berilsa, uni yakunlash uchun sabab bo'lishi mumkin ob'ektning tirilishi, chunki finalistlar o'zboshimchalik bilan kodni ishga tushirishlari mumkin, bu esa jonli ob'ektlardan yo'q qilinadigan narsalarga havolalar yaratishi mumkin. Axlat yig'ilmaydigan tillar uchun bu juda katta xato va sababdir osilgan ma'lumotnomalar va xotira xavfsizligi qoidabuzarliklar; axlat yig'ish bilan shug'ullanadigan tillar uchun bu axlat yig'uvchi tomonidan oldini olinadi, odatda axlat yig'ishga yana bir qadam qo'shiladi (foydalanuvchi tomonidan belgilangan barcha yakunlovchi dasturlarni ishga tushirgandan so'ng, tirilishni tekshiring), bu axlat yig'ishni murakkablashtiradi va sekinlashtiradi.

Bundan tashqari, ob'ektni qayta tiklash ob'ektni yo'q qilish mumkin emasligini anglatadi va patologik holatlarda ob'ekt har doim o'zini tugatishi mumkin va o'zini buzilmas holga keltiradi. Buning oldini olish uchun ba'zi tillar, masalan Java va Python (Python 3.4 dan) faqat bir marta ob'ektlarni tugatadi va tirilgan ob'ektlarni oxiriga etkazmaydi. Konkret ravishda, bu ob'ekt ob'ektma-ob'ekt asosida yakunlanganligini kuzatish orqali amalga oshiriladi. Objective-C shuningdek, shunga o'xshash sabablarga ko'ra yakunlanishni kuzatadi (hech bo'lmaganda so'nggi Apple versiyalarida), tirilishni xato deb hisoblaydi.

Da boshqacha yondashuv qo'llaniladi .NET Framework, ayniqsa C # va Visual Basic .NET, bu erda yakunlash ob'ekt tomonidan emas, balki "navbat" tomonidan kuzatiladi. Bunday holda, agar foydalanuvchi tomonidan aniqlangan yakunlovchi taqdim etilsa, sukut bo'yicha ob'ekt faqat bir marta yakunlanadi (yaratishda yakunlash uchun navbatga qo'yiladi va u tugagandan so'ng o'chiriladi), ammo uni qo'ng'iroq qilish orqali o'zgartirish mumkin GC modul. Qo'ng'iroq qilish orqali yakunlashni oldini olish mumkin GC.SuppressFinalize, bu ob'ektni dekovatsiya qiladigan yoki qo'ng'iroq qilish orqali qayta yoqilgan GC.ReRegisterForFinalize, bu ob'ektni enqueues qiladi. Ular, ayniqsa, resurslarni boshqarish uchun yakuniy ma'lumotni tasarruf etish uslubiga qo'shimcha sifatida ishlatganda yoki uni amalga oshirishda qo'llaniladi ob'ekt havzasi.

Boshlash bilan kontrast

Yakunlash rasmiy ravishda bir-birini to'ldiradi boshlash - initsializatsiya hayotning boshida, yakunlash oxirida bo'ladi - lekin amalda sezilarli farq qiladi. Ikkala o'zgaruvchilar ham, ob'ektlar ham birinchi navbatda qiymatlarni belgilash uchun ishga tushiriladi, lekin umuman olganda faqat ob'ektlar yakunlanadi va umuman qiymatlarni tozalashga hojat yo'q - operatsion tizim tomonidan xotirani ajratish va qayta tiklash mumkin.

Dastlabki qiymatlarni berishdan tashqari, ishga tushirish, avvalambor, resurslarni olish yoki ob'ektni ba'zi bir xizmatda ro'yxatdan o'tkazish uchun ishlatiladi (masalan voqea ishlovchisi ). Ushbu harakatlar nosimmetrik bo'shatish yoki ro'yxatdan o'tkazmaslik harakatlariga ega va ular nosimmetrik tarzda RAIIda bajariladigan finalizatorda ishlov berishlari mumkin. Biroq, ko'plab tillarda, xususan, axlat yig'ish bilan shug'ullanadigan narsalarning ishlash muddati assimetrikdir: ob'ektni yaratish kodning aniq bir nuqtasida deterministik tarzda sodir bo'ladi, ammo ob'ektni yo'q qilish axlat yig'uvchisining qaroriga binoan, aniqlanmagan muhitda sodir bo'ladi. Ushbu nosimmetriklik, tugatishni boshlanishning to'ldiruvchisi sifatida samarali ishlatib bo'lmasligini anglatadi, chunki u o'z vaqtida, belgilangan tartibda yoki belgilangan muhitda sodir bo'lmaydi. Nosimmetriya ob'ektni aniq bir nuqtada yo'q qilish bilan ham qisman tiklanadi, ammo bu holda yo'q qilish va yo'q qilish bir nuqtada sodir bo'lmaydi va ob'ekt "joylashtirilgan, ammo hali ham tirik" holatda bo'lishi mumkin, bu esa kuchni susaytiradi sinf invariantlari va foydalanishni murakkablashtiradi.

O'zgaruvchilar odatda umrining boshida ishga tushiriladi, ammo umrining oxirida yakunlanmaydi - garchi o'zgaruvchiga ob'ekt sifatida qiymat berilgan bo'lsa, ob'ekt yakunlanishi mumkin. Ba'zi hollarda o'zgaruvchilar ham yakunlanadi: GCC kengaytmalari o'zgaruvchilarni yakunlashga imkon beradi.

Bilan ulanish nihoyat

Nomlashda aks ettirilganidek, "yakunlash" va nihoyat ikkalasi ham shunga o'xshash maqsadlarni bajaradi: biron bir yakuniy harakatni bajarish, umuman tozalash, yana bir narsa tugagandan so'ng. Ular paydo bo'lganda farqlanadi - a nihoyat dastur bajarilishi bog'langan qismdan chiqib ketganda, band bajariladi harakat qilib ko'ring band - bu stakni bo'shatish paytida sodir bo'ladi va shu bilan kutish stakasi mavjud nihoyat bandlar, tartibda - yakunlash ob'ektni yo'q qilishda sodir bo'ladi, bu esa xotirani boshqarish uslubiga bog'liq bo'lib, umuman olganda, yakunlashni kutayotgan ob'ektlar to'plami mavjud - ko'pincha uyumda - bu aniq tartibda bo'lishi shart emas.

Biroq, ba'zi hollarda ular bir-biriga to'g'ri keladi. C ++ da ob'ektni yo'q qilish deterministik bo'lib, a nihoyat bandi, ko'lami blok bo'lgan moslamaning tanasi bilan mos keladigan, o'zgaruvchiga ega bo'lgan mahalliy o'zgaruvchiga ega bo'lishi mumkin. harakat qilib ko'ring band - bajarilish ushbu ko'lamdan chiqib ketganda, xuddi a mavjud bo'lganidek, ob'ekt yakunlanadi (yo'q qilinadi) nihoyat band. Shu sababli C ++ da a mavjud emas nihoyat qurish - bu farq shundaki, yakunlash sinf ta'rifida qo'ng'iroq saytida emas, balki destruktor usuli sifatida belgilanadi. nihoyat band.

Aksincha, a nihoyat a bandi korutin, Python generatorida bo'lgani kabi, korutin hech qachon tugamasligi mumkin - faqat har doim hosil beradi va shuning uchun oddiy ijroda nihoyat band hech qachon bajarilmaydi. Agar korutin misollarini ob'ekt sifatida talqin qilsa, u holda nihoyat bandni ob'ektni yakunlovchi deb hisoblash mumkin va shuning uchun misol axlat yig'ilganda bajarilishi mumkin. Python terminologiyasida koroutin ta'rifi generatordir funktsiyasi, uning bir nusxasi generator iterator, va shunday qilib a nihoyat generator funktsiyasidagi band ushbu funktsiyadan kelib chiqqan generator iteratorlarida yakunlovchi bo'ladi.

Tarix

Ob'ektni yo'q qilishning alohida bosqichi sifatida yakunlash tushunchasi paydo bo'lgan Montgomeri (1994),[13] ob'ektni qurishda initsializatsiyani oldingi farqiga o'xshashlik bilan Martin va Odell (1992).[14] Ushbu bosqichgacha bo'lgan adabiyotlar ushbu jarayon uchun "yo'q qilish" dan foydalangan, yakunlash va taqsimlashni ajratmagan va shu davrga tegishli dasturlash tillari, C ++ va Perl kabi, "qirg'in" atamasini ishlatgan. Ta'sirli kitobda "yakunlash" va "yakunlash" atamalari ham ishlatilgan Dizayn naqshlari (1994).[a][15] 1995 yilda Java-ning kiritilishi mavjud edi yakunlash Ushbu atamani ommalashtirgan va uni axlat yig'ish bilan bog'laydigan usullar va shu sababli tillar odatda bu farqni keltirib chiqaradi va "yakunlash" atamasini, ayniqsa axlat yig'ish sharoitida ishlatadi.


Shuningdek qarang

Izohlar

  1. ^ 1994 yilda nashr etilgan, 1995 yil mualliflik huquqiga ega.

Adabiyotlar

  1. ^ Jagger, Perry va Sestoft 2007, p.542, "C ++ da destruktor aniqlangan tartibda chaqiriladi, C # da esa yakunlovchi bo'lmaydi. C # dan aniq xulq-atvorni olish uchun foydalanish kerak Yo'q qiling.
  2. ^ Boem, Xans-J. (2002). Destruktorlar, yakunlovchi va sinxronizatsiya. POPL.
  3. ^ Jagger, Perry va Sestoft 2007, p.542, C ++ destruktorlari va C # finalizatorlari C ++ destruktorlari ma'lum vaqt oralig'ida, ma'lum tartibda va ma'lum ipdan boshqarilishi ma'nosida aniqlanadi. Ular shu tarzda semantik jihatdan juda o'z vaqtida noma'lum nuqtalarda, noma'lum tartibda, noma'lum ipdan va axlat yig'uvchining xohishiga ko'ra ishlaydigan C # finalizatorlaridan farq qiladi.
  4. ^ To'liq: "Biz" destruktor "atamasini nusxani qaytarib olganda bajaradigan a'zo uchun ishlatamiz. Sinflar destruktorlarga ega bo'lishi mumkin; tuzilmalar bunga qodir emas. C ++ dan farqli o'laroq, destruktorni aniq chaqirish mumkin emas. Yo'q qilish -deterministik - siz destruktor qachon qatl qilishini ishonchli bilolmaysiz, faqat ob'ektga barcha havolalar chiqarilgandan so'ng, u biron bir vaqtda amalga oshirilishini aytishdan tashqari.Meros zanjiridagi destruktorlar ko'p avlodlardan eng kichigigacha tartibda chaqiriladi. Hosil qilingan sinf uchun aniq destruktorni chaqirishga hojat yo'q (va hech qanday yo'l yo'q). C # kompilyatori destruktorlarni tegishli CLR vakolatxonasiga kompilyatsiya qiladi. Ushbu versiya uchun, ehtimol, metama'lumotlar bilan ajralib turadigan instansiyani yakunlovchi tushuniladi. kelajakda statik finalizatorlarni taqdim eting; biz statik finalizatorlar yordamida C # ga hech qanday to'siq ko'rmayapmiz. ", 1999 yil 12-may.
  5. ^ Yo'q qiluvchi va finalizator o'rtasidagi farq nima?, Erik Lippert, Erik Lippertning blogi: kodlashdagi ajoyib sarguzashtlar, 21 yanvar 2010 yil
  6. ^ a b Jagger, Perry va Sestoft 2007, p.542, "Ushbu standartning avvalgi versiyasida endi" yakunlovchi "deb ataladigan narsa" destruktor "deb nomlangan. Tajriba shuni ko'rsatdiki," destruktor "atamasi chalkashliklarni keltirib chiqardi va ko'pincha noto'g'ri kutishlarga olib keldi, ayniqsa dasturchilar C ++ ni bilishadi. C ++ da destruktor aniqlangan tartibda chaqiriladi, C # da esa yakunlovchi bo'lmaydi. C # dan aniq xulq-atvorni olish uchun foydalanish kerak Yo'q qiling."
  7. ^ Sinfni buzadiganlar D dagi klassifikatorlar
  8. ^ java.lang, Sinf ob'ekti: yakunlash
  9. ^ https://golang.org/pkg/runtime/#SetFinalizer
  10. ^ a b v "MET12-J. Yakuniylashtiruvchi vositalardan foydalanmang ", Dhruv Mohindra, Java uchun CERT Oracle Secure kodlash standarti, 05. Metodlar (MET)
  11. ^ ob'ekt .__ del __ (o'zini), Python tili ma'lumotnomasi, 3. Ma'lumotlar modeli: "... __del __ () usullar tashqi invariantlarni saqlash uchun zarur bo'lgan mutlaq minimalni bajarishi kerak. "
  12. ^ Xans-J. Boehm, yakunlash, mavzular va Java ™ texnologiyasiga asoslangan xotira modeli, JavaOne konferentsiyasi, 2005 y.
  13. ^ Montgomeri 1994 yil, p.120, "Ob'ektni instantatsiya qilishda bo'lgani kabi, ob'ektni tugatish uchun loyihalash har bir sinf uchun ikkita operatsiyani amalga oshirishdan foyda ko'rishi mumkin - a yakunlash va a tugatish operatsiya. Yakuniylashtirish operatsiyasi boshqa ob'ektlar bilan bog'lanishni buzadi va ma'lumotlar strukturasining yaxlitligini ta'minlaydi. "
  14. ^ Montgomeri 1994 yil, p.119, "A. Instantatsiyasini amalga oshirishni ko'rib chiqing yaratmoq va boshlash Martin va Odell tomonidan taklif qilinganidek, operatsiya. Birinchisi, yangi ob'ektlar uchun omborni ajratadi, ikkinchisi esa ob'ektni spetsifikatsiyalar va cheklovlarga rioya qilish uchun quradi. "
  15. ^ "Har bir yangi sinfda belgilangan dastur uchun qo'shimcha xarajatlar mavjud (boshlash, yakunlash va hk).", "halokatchi C ++ da, o'chirilishi kerak bo'lgan ob'ektni yakunlash uchun avtomatik ravishda chaqiriladigan operatsiya. "

Qo'shimcha o'qish

Tashqi havolalar