Java için bir yıkıcı var mı?


594

Java için bir yıkıcı var mı? Bununla ilgili herhangi bir belge bulamıyorum. Yoksa, aynı etkiyi nasıl elde edebilirim?

Sorumu daha spesifik hale getirmek için, verilerle ilgilenen bir uygulama yazıyorum ve spesifikasyon, uygulamayı orijinal yeni başlatılan durumuna geri getiren bir 'sıfırlama' düğmesinin olması gerektiğini söylüyor. Ancak, uygulama kapatılmadıkça veya sıfırlama düğmesine basılmadıkça tüm verilerin 'canlı' olması gerekir.

Genellikle bir C / C ++ programcısı olmak, bunun uygulanması önemsiz olacağını düşündüm. (Ve böylece en son uygulamayı planladım.) Programımı, sıfırlama düğmesine basıldığında tüm 'canlı' nesneleri yok edebilmem için tüm 'sıfırlanabilir' nesnelerin aynı sınıfta olacağı şekilde yapılandırdım.

Yaptığım tek şey, sadece veri dereference ve çöp toplayıcı onları toplamak için beklemek olduğunu düşünüyordum, kullanıcı tekrar tekrar veri girip sıfırlama düğmesine basarsanız bir bellek sızıntısı olmaz mıydı? Java bir dil olarak oldukça olgun olduğu için de bunun olmasını önlemenin ya da bununla nazikçe mücadele etmenin bir yolu olmalı diye düşünüyordum.


7
Sadece ihtiyacınız olmayan nesnelere referansta bulunursanız bellek sızıntısı olur. Yani programınızda bir hata var. GC ihtiyaç duyduğu şekilde çalışacaktır (bazen daha erken)
Peter Lawrey

17
Verileri nesneler arasında hızla işliyorsanız, sanal makine GC'yi yakında çalıştırmaz. GC'nin her zaman devam edebileceği veya doğru kararlar verebileceği fikri yanlıştır.
Kieveli

1
@Kieveli JVM hata vermeden GC'yi çalıştırmaz mı?
WVrock

4
Evet, Java için onu bir kez yok edecek yıkıcı olsaydı iyi olurdu.
Tomáš Zato - Monica'yı

Yanıtlar:


526

Java, çöp toplanmış bir dil olduğu için, bir nesnenin ne zaman (hatta yok edileceğini) tahmin edemezsiniz. Dolayısıyla, bir yıkıcının doğrudan karşılığı yoktur.

Devralınan bir yöntem var finalize, ancak bu tamamen çöp toplayıcının takdirine bağlı olarak adlandırılıyor. Bu nedenle, açıkça toplanması gereken sınıflar için, kural bir yakın yöntem tanımlamak ve yalnızca akıl sağlığı kontrolü için sonlandırmayı kullanmaktır (yani yakın çağrılmadıysa şimdi yapın ve bir hata kaydedin).

Orada sonuçlandırmak derinlemesine tartışma olurken o soru gerekirse o daha derinlik sağlamalıdır yüzden, son zamanlarda ...


5
Bu bağlamda "close ()", java.lang.Autocloseable içindeki yöntemi ifade ediyor mu?
Sridhar Sarnobat

21
Hayır, AutoCloseable Java 7'de tanıtıldı, ancak 'close ()' kuralı çok daha uzun sürdü.
Jon Onstott

neden bir nesnenin ne zaman (ya da olsa) yok olacağını tahmin edemezsiniz. Bunu tahmin etmenin başka ne yolu var?
dctremblay

@dctremblay nesnesi imhası çöp toplayıcı tarafından yapılır ve çöp toplayıcı uygulama ömrü boyunca asla çalışmayabilir.
Piro, Reinstate Monica'ya

4
finalizeYöntemin Java 9'da kullanımdan kaldırıldığını unutmayın .
Lii

124

Kaynakları dene ifadesine bir göz atın . Örneğin:

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
  System.out.println(br.readLine());
} catch (Exception e) {
  ...
} finally {
  ...
}

Burada artık gerekli olmayan kaynak BufferedReader.close()yöntemde serbest bırakılır . Uygulayan kendi sınıfınızı oluşturabilir AutoCloseableve benzer bir şekilde kullanabilirsiniz.

Bu ifade, finalizekod yapılandırması açısından daha sınırlıdır , ancak aynı zamanda kodun anlaşılmasını ve bakımını kolaylaştırır. Ayrıca, finalizeuygulamanın ömrü boyunca bir yöntemin çağrıldığına dair bir garanti yoktur .


12
Bunun çok az oyu olmasına şaşırdım. Asıl cevap bu.
nurettin

20
Bunun asıl cevap olduğuna katılmıyorum. Bir örnek, birden çok yöntem çağrısında daha uzun bir süre boyunca işlediği bir kaynağa sahipse, kaynaklarla deneme yardımcı olmaz. Söz konusu kaynağı, söz konusu yöntemlerin çağrıldığı oranda kapatmak ve yeniden açmak uygun değilse, genel bir gerçek değil.
Eric

14
Gerçekten, bu asıl cevap değil . Nesnenin yapımı ve kullanımı tamamen ile enkapsüle sürece bir nesne imha yönetmek için bu yapının kullanımı mümkün değildir tryve finallybir çağrı zorlamak için kullanılır obj.finalize(). Ve bu kurulum bile OP: nesne sıfırlama orta-program "sıfırlama" düğmesi tarafından tetiklenen sorunu çözmez.
7yl4r

1
Diğer kullanıcılar bunun uygulama giriş noktanızda yapıldığını göstermiştir. Değişkeninizi global olarak tanımlayın. Deneme ile giriş işlevinde başlatın. Sonunda yeniden başlat (uygulamanız kapatıldığında). Tamamen mümkündür.
TamusJRoyce

1
@nurettin Java 7, daha fazla mantıklı gelmeye yardımcı olursa, soru sorulduğunda sadece 3 aydır vardı.
corsiKa

110

Hayır, burada yıkıcı yok. Bunun nedeni, tüm Java nesnelerinin öbek ayrılması ve çöplerin toplanmasıdır. Açık anlaşma (yani C ++ 'ın silme operatörü) olmadan, gerçek yıkıcıları uygulamanın mantıklı bir yolu yoktur.

Java, sonlandırıcıları destekler, ancak yalnızca yuva, dosya tanıtıcısı, pencere tutamağı, vb. Gibi yerel kaynakların tutamacını tutan nesneler için bir koruma olarak kullanılması amaçlanır. Çöp toplayıcı, sonlandırıcı olmadan bir nesneyi topladığında, serbest bölge ve o kadar. Nesne bir sonlandırıcıya sahip olduğunda, önce geçici bir konuma kopyalanır (unutmayın, burada çöp topluyoruz), daha sonra sonlandırılmayı bekleyen bir sıraya dönüştürülür ve sonra bir Sonlandırıcı iş parçacığı kuyruğu çok düşük öncelikle yoklar ve sonlandırıcıyı çalıştırır.

Uygulamadan çıkıldığında, JVM bekleyen nesnelerin sonlandırılmasını beklemeden durur, bu nedenle sonlandırıcınızın çalışacağına dair neredeyse hiçbir garanti yoktur.


4
Yerel kaynaklardan bahsettiğiniz için teşekkür ederiz - bu, "yıkıcı benzeri" bir yöntemin faydalı olduğu bir alandır.
Nathan Osman

Evet, şu anda aynı sorunla karşı karşıyayım C ++ 'a yerel çağrılar aracılığıyla tahsis edilen kaynakları / kolları serbest bırakıyorum.
nikk

@ddimitrov, teorik olarak java açık anlaşma yapabilir mi? Yoksa bu mantıklı bir çelişki mi?
mils

1
mils naif olarak açık bir yeniden yerleştirme uygulamak ya herhangi bir referans canlı bir nesneye işaret Java varsayımını kıracak. Tüm işaretçileri yineleyebilir ve takma adları geçersiz kılabilirsiniz, ancak bu GC'den daha pahalıdır. Veya bazı doğrusal tip sistemlerini kullanmayı deneyebilirsiniz (Rust'taki "sahiplik" bölümüne bakın), ancak bu büyük bir dil değişikliğidir. Başka seçenekler de vardır (JavaRT kapsamındaki belleğe vb. Bakın), ancak genel olarak açık anlaşma Java diline iyi uymuyor.
ddimitrov

31

Kullanımı finalize () yöntemleri kaçınılmalıdır. Kaynak temizliği için güvenilir bir mekanizma değildir ve çöp toplayıcısında kötüye kullanarak sorunlara neden olabilirler.

Nesnenizde bir ayırma çağrısına ihtiyacınız varsa, örneğin kaynakları serbest bırakmak için, açık bir yöntem çağrısı kullanın. Bu kural mevcut API'larda (ör. Closeable , Graphics.dispose () , Widget.dispose () ) görülebilir ve genellikle try / nihayet yoluyla çağrılır.

Resource r = new Resource();
try {
    //work
} finally {
    r.dispose();
}

Atılan bir nesneyi kullanma girişimleri bir çalışma zamanı istisnası atmalıdır (bkz. IllegalStateException ).


DÜZENLE:

Eğer tüm yaptığım sadece veri dereference ve çöp toplayıcı onları toplamak için beklemek olsaydı, kullanıcı tekrar tekrar veri girip sıfırlama düğmesine basarsanız bellek sızıntısı olmaz mıydı?

Genel olarak, yapmanız gereken tek şey nesnelere başvurmaktır - en azından, bu şekilde çalışması gerekiyordu. Çöp toplama konusunda endişeleriniz varsa, Java SE 6 HotSpot [tm] Sanal Makine Çöp Toplama Ayarı'na (veya JVM sürümünüz için eşdeğer bir belgeye) göz atın.


1
Dereference'ın anlamı bu değildir. "Bir nesnenin son başvurusunu null olarak ayarlayın" değil, bir referanstan değeri almak (okumak), böylece sonraki işlemler için kullanabilirsiniz.

1
Try..finally hala geçerli ve önerilen bir yaklaşım mı? Diyelim ki, önceden finalize () yönteminde yerel bir yöntem çağırıyordum, çağrıyı nihayet maddeye taşıyabilir miyim? class Resource { finalize() { destroy(); } protected native void destroy(); } class Alt_Resource { try (Resource r = new Resource()) { // use r } finalize { r.destroy(); }
aashima

r sonunda bloğa dahil edilmez. Bu nedenle, o noktada destroy diyemezsiniz. Şimdi, kapsamı try bloğundan önce oluşturulacak şekilde düzeltirseniz, çirkin "kaynakları denemeden önce" durumu ile karşılaşırsınız.
userAsh

21

Java 1.7 yayınlandığında, artık try-with-resourcesbloğu kullanma ek seçeneğiniz vardır . Örneğin,

public class Closeable implements AutoCloseable {
    @Override
    public void close() {
        System.out.println("closing..."); 
    }
    public static void main(String[] args) {
        try (Closeable c = new Closeable()) {
            System.out.println("trying..."); 
            throw new Exception("throwing..."); 
        }
        catch (Exception e) {
            System.out.println("catching..."); 
        }
        finally {
            System.out.println("finalizing..."); 
        } 
    }
}

Bu sınıfı c.close()yürütürseniz, tryblok bırakıldığında ve catchve finallybloklar yürütülmeden önce yürütülür. finalize()Yöntemin aksine, close()yürütülmesi garanti edilir. Ancak, finallymaddede açıkça yürütülmesine gerek yoktur .


ya kaynaklar ile dene bloğunu kullanmadıysak? Bence sadece kapatmanın çağrıldığından emin olmak için finalize () işlevinde close diyebiliriz.
shintoZ

3
@shintoZ Yukarıdaki cevapları okuduğumda finalize()yürütme garantisi yok
Asif Mushtaq

14

Sonlandırmanın yürütülmesine güvenmemeyi söyleyerek diğer cevapları tamamen kabul ediyorum.

Try-catch-nihayet bloklarına ek olarak , programınızda son temizlik işlemleri yapmak için Runtime # addShutdownHook'u (Java 1.3'te tanıtıldı) kullanabilirsiniz.

Bu, yıkıcılarla aynı değildir , ancak temizleme yöntemlerinin (kalıcı veritabanı bağlantılarının kapatılması, dosya kilitlerinin kaldırılması vb.) Çağrılabildiği dinleyici nesnelerinin kayıtlı olduğu bir kapatma kancası uygulanabilir - normalde yapılacak şeyler yıkıcılar . Yine - bu yıkıcıların yerine geçmez, ancak bazı durumlarda, bununla istenen işlevselliğe yaklaşabilirsiniz.

Bunun avantajı, yapısızlaştırma davranışını programınızın geri kalanından gevşek bir şekilde birleştirmektir .


addShutdownHook görünüşte Java 1.3'te tanıtıldı. Her neyse, 1.5'te benim için kullanılabilir. :)
Şuna

1
FYI, benim deneyimimde, Eclipse'de kırmızı "sonlandır" düğmesini kullanırsanız kapatma kancaları çağrılmaz - tüm JVM hemen imha edilir, kapatma kancaları incelikle çağrılmaz. Eclipse kullanarak gelişirseniz geliştirme ve üretim sırasında farklı davranışlar görebilirsiniz
Hamy

11

Hayır, java.lang.Object#finalizealabileceğiniz en yakın şey.

Ancak, ne zaman (ve eğer) çağrılırsa, garanti edilmez.
Görmek:java.lang.Runtime#runFinalizersOnExit(boolean)


5
Çağırılabilecek veya çağrılamayacak bir yöntem, kitabımda aslında işe yaramaz. Dili en iyi ihtimalle yanlış bir güvenlik hissi veren işe yaramaz özel bir yöntemle kirletmemek daha iyi olurdu. Java dili düşüncesinin sonuçlandırılmasının neden iyi bir fikir olduğunu asla anlamayacağım.
antred

@antred Java dilinin geliştiricileri aynı fikirde . Sanırım, o zaman, bazıları için, ilk kez çöp toplama ile bir programlama dili ve çalışma ortamı tasarladılar. Daha az anlaşılabilir olan şey, diğer yönetilen dilin bu kavramı, bu kavramın kötü bir fikir olduğu zaten anlaşıldığı bir anda kopyalamasının nedenidir .
Holger

7

İlk olarak, Java çöp toplandığından, nesne imhası hakkında herhangi bir şey yapmanın nadir olduğunu unutmayın. Birincisi, genellikle ücretsiz olarak yönetilen kaynaklarınız olmadığı için ve ikincisi, ne zaman veya ne zaman olacağını tahmin edemeyeceğiniz için, kimse artık nesnesimi kullanmaz kullanmanız gereken şeyler için uygun değildir. ".

Bir nesne java.lang.ref.PhantomReference kullanılarak yok edildikten sonra size bildirilebilir (aslında, yok edildiğini söylemek biraz yanlış olabilir, ancak buna bir hayalet referans sıraya alındığında, artık kurtarılamaz, bu genellikle aynı şey). Ortak kullanım:

  • Sınıfınızdaki başka bir yardımcı nesneye tahrip edilmesi gereken kaynakları ayırın (yaptığınız tek şey ortak bir durum olan bir bağlantıyı kapatmaksa, yeni bir sınıf yazmanız gerekmediğini unutmayın: kapatılacak bağlantı bu durumda "yardımcı nesne" olacaktır).
  • Ana nesnenizi oluşturduğunuzda, ona bir PhantomReference oluşturun. Ya yeni yardımcı nesneye atıfta bulunun ya da PhantomReference nesnelerinden karşılık gelen yardımcı nesnelere bir harita ayarlayın.
  • Ana nesne toplandıktan sonra, PhantomReference sıraya alınır (ya da daha ziyade sıraya alınabilir - finalizörler gibi, bunun hiç bir garantisi yoktur, örneğin VM çıkarsa beklemeyecektir). Sırasını işlediğinizden emin olun (özel bir iş parçacığında veya zaman zaman). Yardımcı nesneye yapılan sert başvuru nedeniyle, yardımcı nesne henüz toplanmamıştır. Bu yüzden yardımcı nesne üzerinde istediğiniz temizliği yapın, ardından PhantomReference'ı atın ve yardımcı da sonunda toplanacaktır.

Bir yıkıcıya benzeyen ancak bir gibi davranmayan finalize () de vardır. Genellikle iyi bir seçenek değildir.


Neden WeakReference yerine PhantomReference?
uckelman

2
@uckelman: İstediğiniz tek şey bildirim ise, PhantomReference işi yaparsa, bu neredeyse tasarlandığı şeydir. WeakReference ek semantiklerine burada gerek yoktur ve ReferenceQueue'nuzun bildirildiği noktada, nesneyi artık WeakReference yoluyla kurtaramazsınız, bu nedenle bunu kullanmanın tek nedeni PhantomReference'ın var olduğunu hatırlamak zorunda kalmamaktır. WeakReference'ın yaptığı herhangi bir ekstra iş muhtemelen ihmal edilebilir, ancak neden bununla uğraşasınız?
Steve Jessop

PhantomReference'de bahsettiğiniz için teşekkür ederiz. Mükemmel değil, ama yine de Hiçbir Şeyden Daha İyi.
Foo

@SteveJessop, hayali bir referansa kıyasla hangi “ekstra iş” in zayıf bir referansı olduğunu düşünüyorsunuz?
Holger

6

finalize()Fonksiyon yıkıcı olduğunu.

Ancak, bunun çağrılır çünkü normalde kullanılmaması gerekir GC sonra ve (hiç değilse) o olur ne zaman söyleyemem.

Dahası, sahip olan nesnelerin yerini değiştirmek için birden fazla GC gerekir finalize().

try{...} finally{...}İfadeleri kullanarak kodunuzdaki mantıklı yerleri temizlemeye çalışmalısınız !


5

Cevapların çoğuna katılıyorum.

Hiçbirine tam olarak güvenmemelisiniz finalizeveyaShutdownHook

Sonuçlandırmak

  1. JVM, bu finalize()yöntemin ne zaman çağrılacağını garanti etmez .

  2. finalize()GC iş parçacığı tarafından yalnızca bir kez çağrılabilir. Bir nesne kendini sonlandırma yönteminden çıkarırsa, finalizetekrar çağrılmaz.

  3. Uygulamanızda, çöp toplama işleminin hiçbir zaman başlatılmadığı bazı canlı nesneleriniz olabilir.

  4. Herhangi ExceptionSonlandırma yöntemiyle atılır GC iş parçacığı tarafından göz ardı edilir

  5. System.runFinalization(true)ve Runtime.getRuntime().runFinalization(true)yöntemler çağırma finalize()yönteminin olasılığını arttırır, fakat şimdi bu iki yöntem kullanımdan kaldırılmıştır. Bu yöntemler, iplik güvenliği ve olası kilitlenme yaratması nedeniyle çok tehlikelidir.

shutdownHooks

public void addShutdownHook(Thread hook)

Yeni bir sanal makine kapatma kancasını kaydeder.

Java sanal makinesi iki tür olaya yanıt olarak kapanır:

  1. En son daemon olmayan iş parçacığı çıktığında veya exit (eşdeğer olarak System.exit) yöntemi çağrıldığında program normal olarak çıkar veya
  2. Sanal makine, ^ C yazmak gibi bir kullanıcı kesintisine veya kullanıcı oturum kapatma veya sistem kapatma gibi sistem genelinde bir olaya yanıt olarak sonlandırılır.
  3. Bir kapatma kancası basitçe başlatılmış ancak başlatılmamış bir iş parçacığıdır. Sanal makine kapatma sırasına başladığında, tüm kayıtlı kapatma kancalarını belirtilmemiş bir sırada başlatır ve aynı anda çalışmasına izin verir. Tüm kancalar bittiğinde, çıkışta sonlandırma etkinleştirildiyse, tüm uyarılmamış sonlandırıcıları çalıştıracaktır.
  4. Son olarak, sanal makine duracaktır. Daemon iş parçacıklarının kapatma sırası sırasında çalışmaya devam edeceğini ve kapatma işlemi çıkış yöntemi çağrılarak başlatılmışsa daemon iş parçacığı olmayan iş parçacıklarının da devam edeceğini unutmayın.
  5. Kapatma kancaları da çalışmalarını hızlı bir şekilde bitirmelidir. Bir program çıkış çağrısında bulunduğunda, sanal makinenin hemen kapanıp çıkması beklenir.

    Ancak Oracle belgeleri bile

Nadir durumlarda sanal makine temiz bir şekilde kapanmadan durdurulabilir, yani çalışmayı durdurabilir

Bu, sanal makine harici olarak, örneğin SIGKILLUnix sinyali veya TerminateProcessMicrosoft Windows çağrısı ile sonlandırıldığında oluşur . Sanal makine, örneğin dahili veri yapılarını bozarak veya mevcut olmayan belleğe erişmeye çalışarak yerel bir yöntem ters giderse de iptal edebilir. Sanal makine iptal edilirse, herhangi bir kapatma kancasının çalıştırılıp çalıştırılmayacağı konusunda hiçbir garanti verilemez.

Sonuç : blokları uygun şekilde kullanın try{} catch{} finally{}ve kritik kaynakları finally(}blokta serbest bırakın . Kaynakların finally{}blok halinde serbest bırakılması sırasında , yakalayın Exceptionve Throwable.


4

Eğer sadece endişelendiğin anı ise, yapma. Sadece GC güven iyi bir iş yapar. Aslında o kadar etkili bir şey gördüm ki, performans için küçük nesneler yığınları oluşturmak bazı durumlarda büyük diziler kullanmaktan daha iyi olabilir.


3

Belki nesneyi kullandığınız kontrol akışındaki nesneyi sonlandırmak için bir try ... son olarak bloğu kullanabilirsiniz. Elbette otomatik olarak gerçekleşmez, ancak C ++ 'da yıkım da olmaz. Son blokta sık sık kaynakların kapatıldığını görürsünüz.


1
Bu, söz konusu kaynağın tek bir sahibine sahip olduğu ve başka bir kod tarafından "çalındığı" referansları olmadığında doğru cevaptır.
Steve Jessop

3

Lombok'ta çoğunlukla C ++ yıkıcılarına benzeyen bir @Cleanup ek açıklaması var:

@Cleanup
ResourceClass resource = new ResourceClass();

İşleme sırasında (derleme zamanında), Lombok yürütme değişkenin kapsamından ayrıldığında çağrılacak uygun try-finallybloğu ekler resource.close(). Ayrıca kaynağı serbest bırakmak için açıkça başka bir yöntem belirtebilirsiniz, örneğin resource.dispose():

@Cleanup("dispose")
ResourceClass resource = new ResourceClass();

2
Gördüğüm avantaj daha az iç içe yerleştirme olacak ("Yok etme" gerektiren çok sayıda nesneniz varsa bu önemli olabilir).
Alexey

Kaynakla deneme bloğu bir kerede birden fazla kaynağa sahip olabilir
Alexander - Monica'yı yeniden eski haline

1
Ancak aralarında talimatlar olamaz.
Alexey

Fuarı. Ben yeni try-ile-kaynak blokları (artan yuvalama) yapmaya zorladı aralarında talimat, daha sonra kullanmak olacaksa gerekli olmadıkça daha sonra öneri, hatta birden fazla kaynak, denemek-ile-kaynak tercih olduğunu varsayalım@Cleanup
Alexander - Reinstate Monica

2

Java'daki bir yıkıcıya en yakın eşdeğer finalize () yöntemidir. Geleneksel bir yıkıcı ile arasındaki en büyük fark, ne zaman çağrılacağından emin olamamanızdır, çünkü bu çöp toplayıcının sorumluluğundadır. Dosya işlemcileri için tipik RAIA modelleriniz kesinleşmeyle () güvenilir bir şekilde çalışmadığından, kullanmadan önce bunu dikkatlice okumanızı şiddetle tavsiye ederim.


2

Burada birçok harika yanıt var, ancak finalize () kullanmaktan neden kaçınmanız gerektiği hakkında bazı ek bilgiler var .

JVM System.exit()veya nedeniyle çıkarsa Runtime.getRuntime().exit(), sonlandırıcılar varsayılan olarak çalışmaz. Gönderen Runtime.exit () için Javadoc :

Sanal makinenin kapatma sırası iki aşamadan oluşur. İlk aşamada, eğer varsa, tüm kayıtlı kapatma kancaları belirtilmemiş bir sırada başlatılır ve bitene kadar aynı anda çalışmasına izin verilir. İkinci aşamada, çıkışta sonlandırma etkinleştirildiyse, tüm uyarılmamış sonlandırıcılar çalıştırılır. Bu yapıldıktan sonra sanal makine durur.

Arayabilirsiniz, System.runFinalization()ancak bir garanti değil, sadece "tüm olağanüstü sonuçlandırmalarını tamamlamak için en iyi çabayı" yapar.

Bir System.runFinalizersOnExit()yöntem var, ama kullanmayın - güvensiz, uzun zaman önce kullanımdan kaldırıldı.


1

Bir Java Uygulaması yazıyorsanız, Applet "destroy ()" yöntemini geçersiz kılabilirsiniz. Bu...

 * Called by the browser or applet viewer to inform
 * this applet that it is being reclaimed and that it should destroy
 * any resources that it has allocated. The stop() method
 * will always be called before destroy().

Açıkçası değil ne sen istemek, ama diğer insanlar aradıklarını olabilir.


1

Sadece orijinal soruyu düşünerek ... diğer tüm öğrenilen cevaplardan ve Bloch'un temel Etkili Java'sından , madde 7, "Sonlandırıcılardan kaçın" sonucuna varabileceğimizi düşünüyorum , meşru bir sorunun çözümünü, Java dili için uygun değil ...:

... OP'nin gerçekte istediği şeyi yapmak için oldukça açık bir çözüm olmazdı, tüm diğer sıfırlanamayan nesnelerin sadece bir tür referansları olduğu bir tür "oyun parkı" nda sıfırlanması gereken tüm nesnelerinizi tutmak erişimci nesnesinin ...

Ve sonra "sıfırlamanız" gerektiğinde, mevcut oyun alanının bağlantısını kesip yeni bir oyun alanı oluşturursunuz: oyun parkındaki nesnelerin tüm ağı, asla geri dönmeyecek ve GC tarafından toplanacak bir gün bekletilecek.

Bu nesnelerden herhangi biri oluşturulduysa Closeable(veya değilse, ancak bir closeyönteminiz varsa) Bag, oluşturulduklarında (ve muhtemelen açıldıklarında) onları oyun alanına koyabilirsiniz ve oyun alanını kesmeden önce erişimcinin son hareketi gitmek olacaktır. bütün aracılığıyla Closeableskapanış onları ...?

Kod muhtemelen şöyle görünecektir:

accessor.getPlaypen().closeCloseables();
accessor.setPlaypen( new Playpen() );

closeCloseablesmuhtemelen JavaFX iş parçacığında uygun şekilde sonlandırılacak herhangi bir iş parçacığında / CountdownLatchile başa çıkmak (ve uygun şekilde beklemek) için bir mandal (örneğin ) içeren bir engelleme yöntemi olacaktır.RunnablesCallablesPlaypen


0

Java'nın GC teknolojisinde önemli ilerlemeler olmasına rağmen, referanslarınıza dikkat etmeniz gerekir. Aslında kaputun altında sıçan yuvaları olan görünüşte önemsiz referans desenleri akla geliyor.

Yayınınızdan, nesnenin yeniden kullanımı (sıfır?) Amacıyla bir sıfırlama yöntemi uygulamaya çalıştığınız anlaşılıyor. Nesnelerinizin temizlenmesi gereken başka türde kaynakları (yani, kapatılması gereken akışlar, döndürülmesi gereken havuzlanmış veya ödünç alınmış nesneler) var mı? Eğer endişelenen tek şey bellek dealloc ise, o zaman benim nesne yapısını yeniden düşünmek ve benim nesneler GC zamanında temizlenecek kendi kendine yeten yapılar olduğunu doğrulamaya çalışın.


0

Java'da tam olarak yok edici bir sınıf yoktur, Java'da çöp toplayıcı tarafından otomatik olarak yok edilen sınıf. ancak bunu bir tanesinin altında kullanarak yapabilirsiniz, ancak tam olarak aynı şey değildir:

Sonuçlandırmak()

Orada sonuçlandırmak derinlemesine tartışma çatallanan bir soru gerekirse daha fazla derinlik almalısınız böylece, ...


0

Java'nın hiçbir yıkıcısı yoktur.Java'da arkasındaki ana neden, her zaman pasif olarak arka planda çalışan Çöp Toplayıcılarıdır ve tüm nesneler yığın belleğinde yapılır, bu GC'nin çalıştığı yerdir. Çöp toplayıcı gibi bir şey olmadığından açıkça silme işlevini çağırmanız gerekir.


-3

Eskiden C ++ ile uğraşırdım ve bu da beni bir yıkıcı arayışına götürdü. Şimdi JAVA kullanıyorum. Yaptığım ve herkes için en iyi durum olmayabilir, ancak tüm değerleri 0 veya varsayılan olarak bir fonksiyon aracılığıyla sıfırlayarak kendi yıkımımı uyguladım.

Misal:

public myDestructor() {

variableA = 0; //INT
variableB = 0.0; //DOUBLE & FLOAT
variableC = "NO NAME ENTERED"; //TEXT & STRING
variableD = false; //BOOL

}

İdeal olarak bu tüm durumlar için işe yaramaz, ancak küresel değişkenlerin olduğu yerlerde, bir tonunuz olmadığı sürece çalışır.

En iyi Java programcısı olmadığımı biliyorum, ama benim için çalışıyor gibi görünüyor.


Değişmez nesneleri daha fazla kullanmaya çalışın, '
anladınız

5
Bu anlamsız olduğu kadar yanlış değil - yani hiçbir şey başaramıyor. Programınız düzgün çalışabilmek için ham türlerin sıfırlanmasını gerektiriyorsa, sınıf örnekleriniz yanlış bir şekilde kapsamlandırılır; başka bir deyişle, varolan bir nesnenin özelliklerini yeni bir Object () oluşturmadan yeni bir nesnenin özelliklerine yeniden atayabilirsiniz.
simo.3792

1
Değişkenleri sıfırlamak için çok fazla ihtiyaç vardır. Yıkıcı adını seçtim çünkü yaptığım şeye uyuyor. Bir şey
ChristianGLong
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.