Nesne dirilişi - Object resurrection

İçinde nesne yönelimli programlama Diller ile çöp toplama, nesne dirilişi ne zaman bir nesne süreci sırasında hayata geri döner nesne yok etme bir yan etkisi olarak sonlandırıcı idam ediliyor.

Nesne dirilişi bir dizi sorunlar özellikle de nesne dirilişi olasılığı - gerçekleşmese bile - çöp toplamayı önemli ölçüde daha karmaşık ve yavaş hale getirir ve sonuçlandırıcıların cesaretinin kırılmasının başlıca nedenidir. Diller, nesne dirilişini çeşitli şekillerde ele alır. çözümler bu sorunlara. Nadir durumlarda, nesne yeniden canlandırma, belirli tasarım modellerini uygulamak için kullanılır. nesne havuzu,[1] diğer durumlarda diriliş, kesinleştiricilerdeki bir hatanın neden olduğu istenmeyen bir hatadır ve genel olarak diriliş önerilmez.[2]

İşlem

Nesne dirilişi aşağıdaki süreçle gerçekleşir. Önce bir nesne olur çöp artık programdan erişilemediğinde ve toplanabilir (imha edilebilir ve serbest bırakılabilir). Ardından, nesne yok etme sırasında, çöp toplayıcı nesneyi serbest bırakmadan önce, sonlandırıcı yöntem çalıştırılabilir, bu da o nesneyi veya başka bir çöp nesnesini (bir sonlandırıcı ile nesneden erişilebilir) ona referanslar oluşturarak tekrar ulaşılabilir hale getirebilir, çünkü bir sonlandırıcı rastgele kod içerebilir. Böyle bir durumda, başvurulan nesne - ki bu mutlaka sonlandırılmış nesne değildir - artık çöp değildir ve ataması kaldırılamaz, aksi takdirde ona yapılan başvurular olur sarkan referanslar ve kullanıldığında hatalara, genellikle programın çökmesine veya öngörülemeyen davranışlara neden olur. Bunun yerine, korumak için bellek güvenliği nesne hayata döndürülür veya dirildi.

Bunu tespit etmek için, bir çöp toplayıcı genellikle iki aşamalı koleksiyon sonlandırıcıların varlığında: önce sonlandırıcıya sahip herhangi bir çöpü sonlandırın ve ardından yeniden kontrol edin herşey çöp (veya sonlandırıcılı nesnelerden erişilebilen tüm çöpler), sonlandırıcıların bazı çöpleri yeniden canlandırması durumunda. Bu ek yük getirir ve bellek ıslahını geciktirir.

Dirilen nesneler

Dirilen bir nesneye diğer nesnelerle aynı muamele edilebilir veya özel olarak ele alınabilir. Pek çok dilde, özellikle C #, Java ve Python'da (Python 3.4'ten), nesneler, bir nesnenin tekrar tekrar diriltilmesi ve hatta yok edilemez olması olasılığını önlemek için yalnızca bir kez sonlandırılır; C # 'da sonlandırıcıları olan nesneler varsayılan olarak yalnızca bir kez sonlandırılır, ancak sonlandırma için yeniden kaydedilebilir. Diğer durumlarda, dirilen nesneler, özellikle Objective-C'de, hata olarak kabul edilir; veya özellikle Python 3.4'ten önceki Python'da diğer nesnelerle aynı şekilde işlem görür.

Dirilen bir nesneye bazen zombi nesnesi veya zombi, ancak bu terim, kullanım dile ve yazara bağlı olarak, nesne imhasıyla ilgili çeşitli nesne durumları için kullanılır. Bir "zombi nesnesinin" özel bir anlamı vardır: Amaç-C ancak aşağıda ayrıntılı olarak anlatılmıştır. Zombi nesneleri biraz benzerdir zombi süreçleri, bir sonlandırma durumu değişikliğine uğramış olmaları ve tahsisi kaldırmaya yakın olmaları bakımından, ancak ayrıntılar önemli ölçüde farklıdır.

Varyantlar

İçinde .NET Framework, özellikle C # ve VB.NET, "nesne dirilişi" bunun yerine bir nesnenin durumunu ifade eder sırasında sonlandırma: nesne hayata döndürülür (erişilemez olmaktan), sonlandırıcı çalıştırılır ve sonra erişilemez duruma geri döndürülür (ve gelecekte sonlandırma için artık kaydedilmez). .NET'te, hangi nesnelerin sonlandırılması gerektiği nesne nesne izlenmez, bunun yerine bir sonlandırma "kuyruğunda" saklanır,[a] bu nedenle, bu makale anlamında yeniden dirilen nesneler kavramından ziyade, "sonlandırma için sıraya alınmış" nesnelerden söz edilmektedir. Ayrıca, nesneler, sonlandırma için yeniden sıralanabilir. GC.ReRegisterForFinalize, nesneleri çoğaltmamaya özen göstererek.[2]

Mekanizma

Bir nesnenin kendisini veya başka bir nesneyi yeniden diriltmesinin iki ana yolu vardır: ulaşabileceği bir nesnede kendisine bir referans oluşturarak (çöp erişilebilir değildir, ancak çöp, çöp olmayan nesnelere başvurabilir) veya içinde bir referans oluşturarak Çevre (genel değişkenler veya bazı durumlarda statik değişkenler veya bir içindeki değişkenler kapatma ). Her ikisinin de Python örnekleri, kendisini dirilten bir nesne için takip eder. Aynı mekanizmalar tarafından belirli bir çöp toplama döngüsünde her ikisi de toplanıyorsa, bir nesnenin diğer nesneleri diriltmesi de mümkündür.

Ulaşabileceği bir nesnede referans oluşturarak kendini diriltir:

sınıf Yapışkan:    def __içinde__(kendini, ref=Yok) -> Yok:        kendini.ref = ref            def __del__(kendini):        Eğer kendini.ref:            kendini.ref.ref = kendini        Yazdır("Beni bırakma!")a = Yapışkan(Yapışkan())  # 2 öğeli bağlantılı bir liste oluşturun,                      # başvurulan | a |a.ref.ref = a  # Bir döngü oluşturuna.ref = Yok  # İlk düğümden referansı temizleme              # ikinciye ikinci çöpü yapara.ref = Yok

Küresel ortamda bir referans oluşturarak kendini diriltiyor:

c = Yoksınıf Ölümsüz:    def __del__(kendini):        küresel c        c = kendini        Yazdır("Henüz ölmedim.")c = Ölümsüz()c = Yok  # Takas | c | nesneyi çöp yaparc = Yok

Yukarıdaki örneklerde, 3.4'ten önceki CPython'da, bunlar sonlandırıcıları tekrar tekrar çalıştıracak ve nesneler çöp olarak toplanmayacak, CPython 3.4 ve sonraki sürümlerde ise sonlandırıcılar yalnızca bir kez çağrılacak ve nesneler çöp olarak toplanacak ikinci kez erişilemez hale gelirler.

Problemler

Nesne dirilişi çok sayıda soruna neden olur.

Çöp toplamayı karmaşıklaştırır
Nesne diriliş olasılığı, çöp toplayıcının sonlandırmadan sonra yeniden dirilen nesneleri kontrol etmesi gerektiği anlamına gelir - gerçekte gerçekleşmese bile - bu da çöp toplamayı karmaşıklaştırır ve yavaşlatır.
Yıkılmaz nesneler
Bazı durumlarda, bir nesne yok edilemez olabilir: bir nesne kendi sonlandırıcıda yeniden dirilirse (veya bir grup nesne, sonlandırıcılarının bir sonucu olarak birbirini diriltirse) ve sonlandırıcı, nesneyi yok ederken her zaman çağrılırsa, o zaman nesne yok edilebilir ve hafızası geri alınamaz.
Kazara diriliş ve sızıntılar
Üçüncüsü, nesne dirilişi kasıtsız olabilir ve ortaya çıkan nesne anlamsal çöp olabilir, bu nedenle hiçbir zaman gerçekten toplanarak mantıksal bir bellek sızıntısı.
Tutarsız durum ve yeniden başlatma
Dirilen bir nesne tutarsız bir durumda olabilir veya ihlal ediyor olabilir sınıf değişmezleri, sonlandırıcının yürütülmesi ve düzensiz bir duruma neden olması nedeniyle. Bu nedenle, dirilen nesnelerin genellikle manuel olarak yeniden başlatılması gerekir.[1]
Benzersiz sonuçlandırma veya yeniden sonuçlandırma
Bazı dillerde (Java ve Python 3.4+ gibi) sonlandırmanın tam olarak nesne başına bir kez gerçekleşmesi garanti edilir, bu nedenle dirilen nesnelerin sonlandırıcıları çağrılmaz; bu nedenle, dirilen nesnelerin, sonlandırıcının dışında gerekli temizleme kodunu yürütmesi gerekir. Diğer bazı dillerde, programcı sonlandırmayı tekrar tekrar yapılmaya zorlayabilir; özellikle, C # vardır GC.ReRegisterForFinalize.[1]

Çözümler

Diller, nesnelerin yeniden dirilişiyle başa çıkmak için birkaç farklı yöntem benimsemiştir; en yaygın olarak, referansların sarkmasını önlemek için sonlandırıcıların varlığında iki aşamalı çöp toplama; ve nesnelerin yok edilebilmesini sağlamak için, özellikle nesneleri sonlandırılmış olarak işaretleyerek (bir bayrak aracılığıyla) nesneleri yalnızca bir kez sonlandırarak.

Java, nesnenin bir kez daha erişilemez olduğunu kanıtlayana kadar nesneyi serbest bırakmayacak, ancak sonlandırıcıyı birden fazla kez çalıştırmayacaktır.[3]

Python'da, Python 3.4'ten önceki standart CPython uygulama, dirilen nesneleri diğer nesnelerle aynı şekilde ele alır (hiçbir zaman sonlandırılmamış olan), yok edilemez nesneleri mümkün kılar.[4] Dahası, nesne dirilişiyle ilgili olası sorunları önlemek için bir sonlandırıcıya sahip bir nesne içeren toplama döngülerini çöpe atmaz. Python 3.4'ten başlayarak, davranış büyük ölçüde Java ile aynıdır:[b] nesneler yalnızca bir kez sonlandırılır ("zaten sonlandırılmış" olarak işaretlenir), döngülerin çöp toplama iki aşamadadır, ikinci aşama yeniden dirilen nesneler için kontrol edilir.[5][6]

Objective-C 2.0 diriltilmiş nesneleri, kendilerine gönderilen tüm mesajları günlüğe kaydedecekleri, ancak başka hiçbir şey yapmadıkları bir "zombi" durumuna sokacaktır.[7] Ayrıca bakınız Otomatik Referans Sayma: Zayıf Referansları Sıfırlama ele almak için zayıf referanslar.

.NET Framework'te, özellikle C # ve VB.NET'te, nesne sonlandırma, bir sonlandırma "kuyruğu" ile belirlenir,[a] Sonlandırıcıya sahip nesneler, oluşturma sırasında bu kuyruğa yerleştirilir ve sonlandırıcı çağrıldığında kuyruğundan çıkarılır, ancak (sonlandırmadan önce) ile manuel olarak kuyruktan çıkarılabilir. SuppressFinalize veya yeniden sıraya alındı ReRegisterForFinalize. Bu nedenle, varsayılan olarak, sonlandırıcılara sahip nesneler en fazla bir kez sonlandırılır, ancak bu sonlandırma bastırılabilir veya nesneler yeniden dirilirse (yeniden erişilebilir hale getirilirse) ve daha sonra sonlandırma için yeniden sıralanırsa birden çok kez sonlandırılabilir. Daha ileri, zayıf referanslar varsayılan olarak dirilişi izleme, yani zayıf bir referans bir nesne yeniden dirilirse güncellenmez; bunlara denir kısa zayıf referanslardirilişi izleyen zayıf referanslara uzun zayıf referanslar.[8]

Başvurular

Nesne dirilişi, bir nesne havuzu yaygın olarak kullanılan nesnelerdir, ancak kodu gizler ve daha kafa karıştırıcı hale getirir.[3] Yalnızca sık kullanılabilecek ve yapımının / imhasının zaman alıcı olduğu nesneler için kullanılmalıdır. Bir örnek, çok sayıda sayının kısa sürede oluşturulduğu ve yok edildiği, ancak aslında aynı anda yalnızca küçük bir sayının kullanımda olduğu bir dizi rastgele sayı olabilir. Nesne dirilişiyle, bir havuzlama tekniği gereksiz yaratma ve yok etme yükünü azaltacaktır. Burada, bir havuz yöneticisi, eğer o anda yok edilecekse, nesneye bir referans biçiminde nesne yığın bilgisine ulaşacaktır. Havuz yöneticisi, nesneyi daha sonra yeniden kullanmak üzere saklar.[9]

Ayrıca bakınız

Notlar

  1. ^ a b Öğeler ortadan kaldırılabildiğinden, bu kesinlikle bir kuyruk değildir. GC.SuppressFinalization.
  2. ^ CPython, döngüsel olmayan atık için ayrı bir döngü algılayıcısı ile referans sayıları kullanırken, Java'nın çoğu uygulaması bir izleme çöp toplayıcısı kullanır.

Referanslar

  1. ^ a b c Goldshtein, Zurbalev ve Flatow 2012, s.129.
  2. ^ a b Richter 2000.
  3. ^ a b "Diriliş (çöp toplamada) nedir?". http://www.xyzws.com/: XYZWS. Alındı 2011-08-01. Çöp toplama için uygun olan bir nesne uygun olmayı bırakıp normal yaşama dönebilir. Bir finalize () yöntemi içinde, bunu bir referans değişkenine atayabilir ve bu nesnenin koleksiyonunu engelleyebilirsiniz; bu, birçok geliştiricinin resurrection dediği bir eylemdir. / Finalize () yöntemi, herhangi bir nesne için JVM tarafından hiçbir zaman birden fazla çağrılmaz. JVM, resurrection'dan sonra finalize () yöntemini tekrar çağırmayacaktır (finalize () yöntemi o nesne için zaten çalıştırıldığı için).
  4. ^ Tim Peters'ın cevabı to "Python'da nesne başına kaç kez "__del__" çağrılabilir? "
  5. ^ Python 3.4'teki Yenilikler, PEP 442: Güvenli Nesne Sonuçlandırma
  6. ^ Pitrou, Antoine (2013). "PEP 442 - Güvenli nesne sonlandırma".
  7. ^ Sonlandırma Yönteminin Uygulanması
  8. ^ Goldshtein, Zurbalev ve Flatow 2012, s.131.
  9. ^ "Nesne dirilişi" (PDF). http://www.hesab.net/: Hesab.net. Alındı 2011-08-01. Nesne yeniden canlandırma, yalnızca olağandışı senaryolarda, örneğin oluşturulması ve yok edilmesi zaman alıcı olan bir nesne havuzunu uygularken yararlı olma olasılığı yüksek olan gelişmiş bir tekniktir. ... ObjectPool demo uygulaması, bir nesne havuzu yöneticisinin, birçok nesne sıklıkla oluşturulduğunda ve yok edildiğinde performansı artırabileceğini gösterir. Bir rasgele sayı dizisini kapsayan bir RandomArray sınıfınız olduğunu varsayalım. Ana program, belirli bir anda yalnızca birkaç nesne canlı olsa bile, binlerce RandomArray nesnesi oluşturur ve yok eder. Sınıf, yapıcı yönteminde (zaman alıcı bir işlem) rastgele dizi oluşturduğundan, bu durum bir havuzlama tekniği için idealdir. ... Havuzlama tekniğindeki en önemli nokta, PoolManager sınıfının havuzdaki (PooledObjects Yığın nesnesinde) kullanılmayan nesnelere bir başvuru içermesi, ancak ana program tarafından kullanılan nesnelere bir başvuru içermemesidir. Aslında, son nesneler yalnızca ana programdaki referanslarla canlı tutulur. Ana program bir RandomArray nesnesini Nothing olarak ayarladığında (veya kapsamın dışına çıkmasına izin verdiğinde) ve bir çöp toplama gerçekleştiğinde, çöp toplayıcı nesnenin Finalize yöntemini çağırır. Bu nedenle, RandomArray’ın Finalize yöntemindeki kod, PoolManager’ın PooledObjects yapısında kendisine bir başvuru depolayarak kendini yeniden canlandırma fırsatına sahiptir. Dolayısıyla, NewRandomArray işlevi tekrar çağrıldığında, PoolManager nesnesi, yeni bir tane oluşturmanın zaman alıcı sürecinden geçmeden havuzlanmış bir nesneyi istemciye döndürebilir.