Java nesnelerini null olarak ayarlamak artık bir şey yapıyor mu?


112

Bazı eski kitaplara göz atıyordum ve Peter Hagger'ın "Pratik Java" nın bir kopyasını buldum. Performans bölümünde, nullartık ihtiyaç duyulmadığında nesne referanslarının ayarlanması önerilmektedir .

Java'da, nullperformansı veya atık toplama verimliliğini artırmak için nesne referansları ayarlamak mı? Eğer öyleyse, bu hangi durumlarda bir sorundur? Konteyner sınıfları? Nesne bileşimi? Anonim iç sınıflar?

Bunu kodda oldukça sık görüyorum. Bu artık eski programlama tavsiyesi mi yoksa hala yararlı mı?


2
Profili. Modern çalışma zamanlarında, performansta veya bellek ayak izinde anlamlı bir artış görmemelisiniz.
Jason Coco

12
@Jason, Profili? Bu, bunu yanıtlamak için yeterince iyi bir sonuç kümesi elde etmek için yeterince büyük bir vaka kümesinin profilini çıkaracağımı varsayar. Ve sanal makinenin gc ve performans sorunlarını maskelemek için yeterince optimize edildiği bir dizi durum seçmediğimi. Bu yüzden bunu burada soruyorum. Bunun bir sorun olduğu durumları anlamak için.
sal

Yanıtlar:


73

Referansı ne zaman geçersiz kılmayı düşündüğünüze biraz bağlıdır.

Bir nesne zinciriniz A-> B-> C varsa, A'ya ulaşılamadığında, A, B ve C'nin tümü çöp toplama için uygun olacaktır (başka hiçbir şeyin B veya C'ye atıfta bulunmadığı varsayılarak). Örneğin, A-> B veya B-> C referanslarını açıkça null olarak ayarlamaya gerek yoktur ve hiçbir zaman gerek duyulmamıştır.

Bunun dışında, çoğu zaman sorun gerçekten ortaya çıkmıyor çünkü gerçekte koleksiyonlardaki nesnelerle uğraşıyorsunuz. Genellikle her zaman uygun remove () yöntemini çağırarak nesneleri listelerden, haritalardan vb. Kaldırmayı düşünmelisiniz.

Referansları boşa atamak için bazı tavsiyelerin olduğu durum , özellikle, kapsamın ortasında bellek yoğun bir nesnenin kullanılmasının sona erdiği uzun bir kapsamdaydı . Örneğin:

{
  BigObject obj = ...
  doSomethingWith(obj);
  obj = null;             <-- explicitly set to null
  doSomethingElse();
}

Buradaki mantık, obj hala kapsam dahilinde olduğu için, referansın açık bir şekilde boş bırakılması olmadan, doSomethingElse () yöntemi tamamlanıncaya kadar çöp toplanabilir hale gelmemesidir . Ve bu muhtemelen modern JVM'lerde geçerli olmayan tavsiyedir : JIT derleyicisinin, belirli bir yerel nesne referansının artık kullanılmadığı noktada çalışabileceği ortaya çıktı.


2
Yerel değişkenler makine tarafından optimize edilebilir. Sınıf değişkenleri olamaz. İşçi iş parçacığının (iş parçacığı havuzunda), isteği işledikten sonra durum nesnelerini serbest bırakmadığını ve böylece çalışan iş parçacığına yeni bir görev verilene kadar bu nesneleri bellekte sabitlediklerini gördüm (bu, eski durum nesnelerinin üzerine hemen yenilerini yazdı). Büyük durum nesneleri ve yüzlerce çalışan iş parçacığı ile (düşünün: büyük http sunucusu), bu büyük miktarda bellek tutulabilir ve etrafta kopyalanabilir, ancak bir daha asla kullanılmayacaktır.
Brian White

1
Muhtemelen şunu eklemeliyim: Yukarıda verdiğim tavsiye, iyi huylu kütüphaneler, iyi huylu bir sanal makine vb. Varsayarak genel olarak takip etmem gereken tavsiyelerdir. bir iş bitti, pekala ... bu, söz konusu iş parçacığı havuzu kitaplığındaki bir nesne başvurusunu geçersiz kılarak düzeltilebilecek bir hatadır, ancak aynı şekilde daha az hatalı iş parçacığı havuzu kitaplığı kullanılarak da çözülebilir. Böyle bir hatanın genel tasarım prensiplerini değiştirdiğinden emin değilim.
Neil Coffey

25

Hayır, bu eski bir tavsiye değil. Sarkan referanslar, özellikle ArrayListönceden tahsis edilmiş bir dizi kullanarak genişletilebilir bir dizi kapsayıcısı ( veya benzeri) uyguluyorsanız, hala bir sorundur . Listenin "mantıksal" boyutunun ötesindeki öğeler boş bırakılmalıdır, aksi takdirde serbest bırakılmazlar.

Bkz. Etkili Java 2. baskı, Madde 6: Eski Nesne Referanslarını Ortadan Kaldırın.


Bu bir dil sorunu mu yoksa sanal makine uygulama sorunu mu?
Pablo Santa Cruz

4
Bu "anlamsal" bir sorun. Temel olarak, bir diziyi önceden tahsis ettiğiniz için, VM bunu görür. Konteynırınızın "mantıksal" boyutu hakkında hiçbir şey bilmiyor. 16 elemanlı bir dizi tarafından desteklenen, 10 boyutunda bir ArrayList'iniz olduğunu varsayalım. VM, 10..15 öğelerinin gerçekten kullanılmadığını bilemez; bu yuvaların içeriği varsa, serbest bırakılmayacaktır.
Chris Jester-Young

Peki ya konteyner sınıfları dışında? İç nesnenin dış nesne tarafından ayrılmadığı nesne kompozisyonunda.
sal

7
@sal Genel kural şudur, eğer ona başvuramazsanız, çöplerin toplanmasıdır. Dolayısıyla, dış nesne başka bir nesneye bir başvuru içeriyorsa, iç nesnenin başka herhangi bir başvurusu olmadığını varsayarak, dış nesnenin bir ve yalnızca başvurusunu boş olarak ayarlamak, sahipsiz referanslar da dahil olmak üzere tüm nesnenin çöp olarak toplanmasına neden olur.
ubermensch

2
Aynı Madde 6'da bahsettiğiniz: Nesne referanslarını geçersiz kılmak normdan çok istisna olmalıdır.
ACV

10

Örnek alanları, dizi öğeleri

Bir nesneye referans varsa, çöp toplanamaz. Özellikle bu nesne (ve arkasındaki tüm grafik) büyükse, çöp toplamayı durduran tek bir referans vardır ve bu referansa artık gerçekten ihtiyaç duyulmaz, bu talihsiz bir durumdur.

Patolojik durumlar, onu yapılandırmak için kullanılan XML DOM ağacının tamamında tek olmayan bir örneği tutan nesnedir, kayıtsız olmayan MBean veya tüm sınıf yükleyicinin kaldırılmasını önleyen dağıtılmamış bir web uygulamasından bir nesneye yapılan tek başvuru .

Dolayısıyla, referansı tutan nesnenin yine de (veya o zaman bile) çöp olarak toplanacağından emin değilseniz, artık ihtiyacınız olmayan her şeyi geçersiz kılmalısınız.

Kapsamlı değişkenler:

Yerel bir değişkeni kapsamının sonundan önce boş olarak ayarlamayı düşünüyorsanız, böylece çöp toplayıcı tarafından geri alınabilir ve "şu andan itibaren kullanılamaz" olarak işaretlenebilir, bunun yerine onu daha sınırlı bir kapsam içine koymayı düşünmelisiniz. .

{
  BigObject obj = ...
  doSomethingWith(obj);
  obj = null;          //   <-- explicitly set to null
  doSomethingElse();
}

olur

{
  {  
     BigObject obj = ...
     doSomethingWith(obj);
  }    //         <-- obj goes out of scope
  doSomethingElse();
}

Uzun, düz kapsamlar genellikle kodun okunabilirliği açısından da kötüdür. Sırf bu amaçla işleri parçalamak için özel yöntemler sunmak da duyulmamış bir şey değil.


Güçlü bir referansa atıfta bulunuyorsanız, evet bu doğrudur, ancak tüm referanslar için değil. Java'daki zayıf referanslar çöp toplanabilir.
James Drinkard

5

Hafızayı kısıtlayan ortamlarda (örn. Cep telefonları) bu yararlı olabilir. Null olarak ayarlandığında, objetc değişkeninin gc'de kapsam dışına çıkmasını beklemesine gerek kalmaz.

Bununla birlikte, günlük programlama için, Chris Jester-Young'ın aktardığı gibi özel durumlar dışında bu bir kural olmamalıdır.


1

Birincisi, bir nesneyi ayarladığınız hiçbir şey anlamına gelmez null. Aşağıda açıklıyorum:

List list1 = new ArrayList();
List list2 = list1;

Yukarıdaki kod segmentinde , bellekte depolanan nesnenin nesne referans değişken adını list1oluşturuyoruz ArrayList. O list1nesneye atıfta bulunmak da bir değişkenden başka bir şey değildir. Ve kodun ikinci satırında biz referansı kopyalama list1için list2. Öyleyse şimdi sorarsam sorunuza geri dönelim:

list1 = null;

bu list1, bellekte saklanan herhangi bir nesneye artık atıfta bulunmadığı anlamına gelir , bu nedenle list2de başvuracak hiçbir şey olmayacaktır. Yani şu boyutlara bakarsanız list2:

list2.size(); //it gives you 0

Böylece burada " nesne tarafından tutulan belleği serbest bırakmak konusunda endişelenmenize gerek yok, artık programda kullanılmayacağını ve JVM'nin beni yöneteceğini bulduğumda bunu yapacağım " diyen çöp toplayıcı kavramı gelir .

Umarım kavramı açıklar.


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.