Neden sonlandırma yöntemi Java’ya dahil edildi?


44

Bu göreve göre , çağrılacak kesinleştirme yöntemine asla güvenmemeliyiz. Peki, Java neden bunu programlama dilinde içeriyor?

Bu herhangi bir programlama dilinde bir işlev eklemeyi korkunç bir karar gibi görünüyor olabilir denilen olsun.

Yanıtlar:


41

Joshua Bloch'un Etkili Java'sına (İkinci Basım) göre, finalize()faydalı olduğunda iki senaryo vardır :

  1. Birincisi, bir nesnenin sahibinin açık sonlandırma yöntemini çağırmayı unutması durumunda “güvenlik ağı” olarak davranmaktır. Sonlandırıcının derhal çalıştırılacağına dair hiçbir garanti bulunmamakla birlikte, müşterinin kesin sonlandırma yöntemini kullanamadığı durumlarda (umarım ender görülen) durumlarda, kaynağı hiç olmadığı kadar geç serbest bırakmak daha iyi olabilir. Ancak, sonlandırıcı kaynağın sonlandırılmadığını tespit ederse bir uyarı kaydı yapmalıdır.

  2. Kesinleştiricilerin ikinci meşru kullanımı, yerel akranları olan nesnelerle ilgilidir. Yerel eş, normal bir nesnenin yerel yöntemlerle temsil ettiği yerel bir nesnedir. Yerel bir eş normal bir nesne olmadığından, çöp toplayıcı bunun hakkında hiçbir şey bilmez ve Java eşi geri alındığında onu geri alamaz. Bir kesinleştirici, yerel akranların kritik kaynakları olmadığını varsayarak, bu görevi gerçekleştirmek için uygun bir araçtır. Yerel akran derhal sonlandırılması gereken kaynakları içeriyorsa, sınıf yukarıda açıklandığı gibi açık bir sonlandırma yöntemine sahip olmalıdır. Sonlandırma yöntemi, kritik kaynağı serbest bırakmak için ne gerekiyorsa yapmalıdır.

Daha fazla okumak için, bkz. Madde 7, Sayfa 27.


4
# 2 ile yerel akran gibi sesler güvenlik ağı gerektiren ve bir sonlandırma yöntemine sahip olmalı ve bu nedenle ayrı bir nokta olmamalıdır.
Mooing Duck

2
@MooingDuck: # 2 ayrı bir nokta çünkü yerel eş kritik kaynaklar içermiyorsa (örn. Tamamen bellek içi bir nesne ise), o zaman açık bir sonlandırma yöntemini göstermeye gerek yoktur. # 1'den gelen güvenlik ağı açıkça bir sonlandırma yöntemine sahip olmakla ilgilidir.
jhominal

55

Kesinleştiriciler yerel kaynakların yönetimi için önemlidir. Örneğin, nesnenizin Java dışı bir API kullanarak işletim sisteminden bir WidgetHandle ayırması gerekebilir. Nesneniz GC'dken bu WidgetHandle'ı serbest bırakmazsanız, WidgetHandles'ı sızdırıyor olacaksınız.

Önemli olan, "kesinleştirici asla çağrılmaz" durumlarının basitçe parçalanmasıdır:

  1. Program hızla kapanıyor
  2. Programın ömrü boyunca “sonsuza dek yaşar” nesnesi
  3. Bilgisayar kapanıyor / işleminiz OS / etc tarafından öldürülüyor

Bu üç durumun hepsinde, ya yerel bir sızıntınız yok (programınızın artık çalışmaması nedeniyle) ya da zaten yerel olmayan bir sızıntınız var (eğer olmadan yönetilen nesneleri ayırmaya devam ederseniz) GC'd).

"Sonlandırıcının aranmasına güvenmeyin" uyarısı, program mantığı için sonlandırıcıların kullanılmaması hakkındadır. Örneğin, inşaat sırasında bir dosyadaki bir sayacı artırarak ve bir sonlandırıcıda azaltarak nesnelerinizin programın tüm örneklerinde ne kadar varlığını takip etmek istemezsiniz - çünkü nesnelerinizin olacağının garantisi yoktur. sonlandırılmış olması durumunda, bu dosya sayacı muhtemelen 0'a geri dönmeyecektir. Bu, gerçekten normal şekilde sona eren programınıza bağlı olmamanız gereken daha genel bir ilkenin özel bir durumudur (elektrik kesintileri, vb.).

Yerel kaynakların yönetimi için, kesinleştiricinin çalışmadığı durumlar, çalışmamasını önemsemediğiniz durumlara karşılık gelir.


Mükemmel cevap Aranıyor olsa bile gibiydim .. hala dahil edilmeli. Bir süre soru ve StackOverflow'taki bağlantı ile karıştırıldım.
InformedA

3
Soruda değildi, ancak “çağrılan sonlandırıcıya güvenmeyin” bağlamında tartışmaya değer: sonlandırıcı çağrılabilir, ancak yalnızca nesneye erişilemez hale geldikten sonra keyfi olarak uzun bir gecikmeden sonra çağrılabilir. Bu, bellekten çok daha az olan “çoğu yerel kaynak” için önemlidir (çoğu çıkıyor).

26
"Finalizatörler, yerel kaynakların yönetimi için önemlidir." - hayıroooooooo, üzgünüm. Yerel kaynakları yönetmek için sonlandırıcıları kullanmak korkunç bir fikirdir (bu nedenle şimdi otomatik olarak kapatılabilir ve ortak çalışmamız var). GC sadece herhangi bir kaynağa değil sadece hafızaya önem verir. Bu, yerel kaynakların tükenebileceği, ancak hala bir GC'yi tetiklememek için yeterli belleğe sahip olabileceğiniz anlamına gelir - gerçekten istemiyoruz. Ayrıca sonlandırıcılar GC'yi daha pahalı kılar ve bu da iyi bir fikir değildir.
Voo,

12
Hâlâ finalizers dışındaki açık bir yerli kaynak yönetimi stratejisine sahip olmalı katılıyorum ama senin nesne eğer yapar onları ayırmak ve sonlandırıcıyı bunları boşaltmak değil nesne, nerede olduğunu halinde bir yerli sızıntı kendinizi açıyoruz Kaynaksız bir şekilde serbest bırakılmadan GC'd. Başka bir deyişle, kesinleştiriciler, genel olarak soruna bir çözüm değil, yerel bir kaynak yönetimi stratejisinin önemli bir parçasıdır .
Ryan Cavanaugh

1
@Voo, nesnenin sözleşmesinin takip edilmemesi durumunda kesinleştiricinin geri dönüş olduğunu söylemek muhtemelen daha doğrudur ( close()asla ulaşılamaz hale gelmeden önce asla aranmaz )
cırcır ucube

5

Bu yöntemin amacı API belgelerinde aşağıdaki şekilde açıklanmıştır :

Java sanal makinesinin, başka bir nesnenin sonlandırılmasıyla gerçekleştirilen bir işlemin bir sonucu dışında, henüz ölmemiş herhangi bir iş parçacığı tarafından bu nesneye erişilebileceği herhangi bir yol bulunmadığının tespit edilip edilmediği zaman çağrılır. veya kesinleşmeye hazır olan sınıf ...

finalize... genel amacı , nesne geri alınamaz şekilde atılmadan önce temizleme eylemlerini gerçekleştirmektir . Örneğin, bir giriş / çıkış bağlantısını temsil eden bir nesnenin sonlandırma yöntemi, nesne kalıcı olarak atılmadan önce bağlantıyı kesmek için açık G / Ç işlemleri gerçekleştirebilir ...


Dil tasarımcılarının neden “nesne geri dönülmez şekilde atıldığını” ( çöp toplandı ), uygulama programcısı kontrolünün ötesinde (“asla güvenmemeliyiz”) şeklini seçme nedenleriyle ilgileniyorsanız, ilgili soru :

otomatik çöp toplama ... C ve C ++ programcılarının yatkın olduğu tüm programlama hataları sınıflarını ortadan kaldırır. Java kodunu, sistemin hızlıca birçok hatayı bulacağına ve büyük sorunların üretim kodunuz gönderilinceye kadar uykuda kalmayacağına emin olarak geliştirebilirsiniz.

Yukarıda alıntı, Java tasarım hedefleriyle ilgili resmi belgelerden alınmıştır , yani Java dili tasarımcılarının neden bu şekilde karar verdiğini açıklayan yetkili referans olarak kabul edilebilir.

Bu tercihin daha ayrıntılı ve dille ilgili agnostik bir tartışması için, bkz. OOSC bölüm 9.6 Otomatik bellek yönetimi (aslında, yalnızca bu bölümle değil, aynı zamanda bölüm 9'un tümü, eğer böyle bir şeyle ilgileniyorsanız, okumaya değer). Bu bölüm açık bir ifadeyle açılır:

İyi bir OO ortamı, erişilemeyen nesneleri algılayan ve geri alan, uygulama geliştiricilerin iş - uygulama geliştirmelerine odaklanmalarını sağlayan otomatik bir bellek yönetim mekanizması sunmalıdır.

Yukarıdaki tartışma, böyle bir tesisin mevcut olmasının ne kadar önemli olduğunu göstermeye yeterli olmalıdır. Michael Schweitzer ve Lambert Strether'in sözleriyle:

Otomatik bellek yönetimine sahip olmayan bir nesne yönelimli program kabaca emniyet valfi olmayan bir düdüklü tencere ile aynıdır: er ya da geç, her şey patlayacak!


4

Sonlandırıcılar, işlerin temizlenmesini sağlamak için etkili bir araç olmaları beklendiğinden (pratikte olmasalar da) ve icat edildiklerinde daha iyi temizlik sağlama yöntemleri (hayali referanslar ve deneme gibi) vardır. -resources) henüz bulunmadı. Gezinti sırasında, "sonlandırma" tesisini uygulamak için harcanan çaba başka temizlik araçlarına harcanmış olsaydı, ancak Java başlangıçta geliştirildiği sırada pek açık değildi.


3

CAVEAT: Güncel değil olabilirim, fakat birkaç yıl önceki anlayış benim.

Genel olarak, bir sonlandırıcının ne zaman çalıştığını - ya da hiç çalıştığını garanti etmez - yine de, bazı JVM'ler programın sona ermesinden önce tam bir GC ve sonlandırma talep etmenize izin verecektir (ki bu, programın daha uzun süreceği anlamına gelir) çıkmak ve varsayılan çalışma modu hangisi değildir).

Ve bazı GC'lerin kesinleştiricilere sahip olan GC'ing nesnelerini açıkça geciktirdiği ya da önlediği, bunun benchmarklarda daha iyi performans sağlayacağı umuduyla bilinmektedir.

Bu davranışlar maalesef kesinleştiricilerin önerilmesinin orijinal nedenleriyle çelişiyor ve bunun yerine açıkça adlandırılan kapatma yöntemlerinin kullanılmasını teşvik ediyor.

Atılmadan önce gerçekten temizlenmesi gereken bir nesneniz varsa ve bunu yapmak için kullanıcılara gerçekten güvenemiyorsanız, bir sonlandırıcı yine de dikkate değer olabilir. Ancak, genel olarak, modern Java kodlarında bunları, bazı eski örneklerde yaptığınız kadar sık ​​görmemenizin İyi Sebepleri vardır.


1

Google Java Stil Kılavuzu konuda biraz adaçayı tavsiyesi var:

Öyle çok nadir geçersiz kılmak için Object.finalize.

İpucu : Yapma. Kesinlikle yapmanız gerekiyorsa, ilk önce Effective Java Item 7'yi, "Finaliser'lerden Kaçının" okuyup anladığınızdan emin olun ve sonra yapmayın.


5
Neden problemin aşırı basitleştirildiğine hayranım, "yapma", "neden var" için bir cevap değil.
Pierre Arlaud

1
Sanırım cevabımı iyi hecelemedim, ama (IMO) cevabı "neden var?" "olmamalı" dır. Bir sonlandırma işlemine gerçekten ihtiyaç duyduğunuz nadir durumlarda, muhtemelen kendiniz PhantomReferenceve bununla kendiniz inşa etmek istersiniz ReferenceQueue.
Daniel Pryden

Demek istemiştim * açıkçası, seni reddetmeme rağmen. Ancak en çok oy alan cevap, yöntemin ne kadar faydalı olduğunu gösteriyor, bu da amacınızı geçersiz kılıyor.
Pierre Arlaud

1
Yerel akran durumunda bile, bence PhantomReferencedaha iyi bir çözüm. Sonlandırıcılar, Java'nın ilk günlerinden kalan bir siğildir ve benzerleri Object.clone()ve ham türleri, en iyi unutulan dilin bir parçasıdır.
Daniel Pryden

1
Kesinleştiricilerin tehlikeleri C # 'da daha erişilebilir (geliştiriciler tarafından anlaşılabilir) bir şekilde tanımlanmıştır. , Olsa, bir etmemelidir Java ve C # üzerinde yatan mekanizmalar aynı olduğunu ima; özelliklerinde böyle söyleyen hiçbir şey yok.
rwong,

1

Java Dil Özellikleri (Java SE 7) devletler:

Sonlandırıcılar, otomatik bir depolama yöneticisi tarafından otomatik olarak serbest bırakılamayan kaynakları serbest bırakma şansı sunar. Bu gibi durumlarda, sadece bir nesnenin kullandığı hafızayı geri almak, sahip olduğu kaynakların geri kazanılmasını garanti etmeyecektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.