Sorduğunuz şey oldukça zor bir soru. Bunun sadece bir soru olduğunu düşünebilirsiniz, ancak aslında aynı anda birkaç soru soruyorsunuz. Bunu kapsamak zorunda olduğum bilgisiyle elimden geleni yapacağım ve umarım bazıları kaçırabileceğim şeyi kapsayacak şekilde katılacak.
İç İçe Sınıflar: Giriş
Java'da OOP ile ne kadar rahat olduğunuzdan emin olmadığım için, bu birkaç temel konuyu vuracak. İç içe sınıf, başka bir sınıfta sınıf tanımının bulunduğu zamandır. Temel olarak iki tür vardır: Statik İç İçe Sınıflar ve İç Sınıflar. Bunlar arasındaki gerçek fark:
- Statik İç İçe Sınıflar:
- "Üst düzey" olarak kabul edilir.
- Kapsayıcı sınıfın bir örneğinin oluşturulmasını gerektirmez.
- Açık bir referans olmadan içeren sınıf üyelerine başvuramaz.
- Kendi ömürleri var.
- İç Yuvalanmış Sınıflar:
- Her zaman içeren sınıfın bir örneğinin oluşturulmasını gerektirir.
- İçeren örneğe otomatik olarak örtük başvuru var.
- Referans olmadan kabın sınıf üyelerine erişebilir.
- Ömür boyu olan sözde artık kaba göre daha olmaktır.
Çöp Toplama ve İç Sınıflar
Çöp Toplama otomatiktir ancak kullanıldığını düşünüp düşünmediğine göre nesneleri kaldırmaya çalışır. Çöp Toplayıcı oldukça akıllıdır, ancak kusursuz değildir. Yalnızca nesneye etkin bir başvuru olup olmadığına göre bir şeyin kullanılıp kullanılmadığını belirleyebilir.
Burada asıl mesele, bir iç sınıfın konteynerinden daha uzun süre canlı tutulmasıdır. Bunun nedeni, kapsayıcı sınıfa örtük başvurudır. Bunun olabilmesinin tek yolu, içeren sınıfın dışındaki bir nesnenin, içerdiği nesneye bakılmaksızın iç nesneye bir referans tutmasıdır.
Bu, iç nesnenin canlı olduğu (başvuru yoluyla) bir duruma neden olabilir, ancak içeren nesneye yapılan referanslar diğer tüm nesnelerden zaten kaldırılmıştır. Bu nedenle iç nesne, içerdiği nesneyi canlı tutmaktır, çünkü her zaman bir referansı olacaktır. Bununla ilgili sorun, programlanmadığı sürece, içeride olup olmadığını bile kontrol etmek için içeren nesneye geri dönmenin bir yolu olmamasıdır.
Bu gerçekleşmenin en önemli yönü, bir Faaliyette mi yoksa çekilebilir mi olduğu konusunda hiçbir fark yaratmamasıdır. Sen olacak hep iç sınıfları kullanarak ve kabın onlar asla outlive nesneler emin olduğunda metodik olmak zorunda. Neyse ki, kodunuzun temel bir nesnesi değilse, sızıntılar karşılaştırıldığında küçük olabilir. Ne yazık ki, bunlar bulmak için en zor sızıntılardan bazılarıdır, çünkü birçoğu sızana kadar fark edilmeyeceklerdir.
Çözümler: İç Sınıflar
- İçeren nesneden geçici referanslar alın.
- İç nesneler için uzun ömürlü referanslar tutabilen tek nesne olmasını sağlayın.
- Fabrika gibi yerleşik kalıpları kullanın.
- İç sınıf, kapsayıcı sınıf üyelerine erişim gerektirmiyorsa, bunu statik bir sınıfa dönüştürmeyi düşünün.
- Bir Faaliyette olup olmadığına bakılmaksızın dikkatli kullanın.
Faaliyetler ve Görüşler: Giriş
Faaliyetler, çalıştırıp görüntüleyebilmek için birçok bilgi içerir. Faaliyetler, bir Görüşe sahip olmaları gereken özelliklerle tanımlanır. Ayrıca belirli otomatik işleyicileri var. Belirtip belirtmediğinizde, Etkinliğin içerdiği Görünüme dolaylı bir referansı vardır.
Bir Görünümün oluşturulabilmesi için, nerede oluşturulacağını ve görüntülenebilmesi için alt öğesi olup olmadığını bilmesi gerekir. Bu, her Görünümün Etkinliğe (üzerinden getContext()
) bir referansı olduğu anlamına gelir . Dahası, her Görüş çocuklarına atıfta bulunur (yani getChildAt()
). Son olarak, her Görünüm, görüntüsünü temsil eden oluşturulan Bitmap'e bir referans tutar.
Bir Etkinliğe (veya Etkinlik Bağlamına) başvurunuz olduğunda, düzen hiyerarşisinde ENTIRE zincirini takip edebileceğiniz anlamına gelir. Bu nedenle Etkinlikler veya Görüşlerle ilgili bellek sızıntıları çok büyüktür. Bir kerede bir ton bellek sızdırabilir.
Etkinlikler, Görüşler ve İç Sınıflar
İç Sınıflar hakkında yukarıdaki bilgiler göz önüne alındığında, bunlar en yaygın bellek sızıntılarıdır, ancak aynı zamanda en yaygın şekilde kaçınılır. Bir iç sınıfın bir Activities sınıfı üyelerine doğrudan erişimi olması arzu edilirken, birçoğu potansiyel sorunları önlemek için onları statik hale getirmeye isteklidir. Etkinlikler ve Görüşlerle ilgili sorun bundan çok daha derin.
Sızan Etkinlikler, Görüşler ve Etkinlik Bağlamları
Her şey Bağlam ve Yaşam Döngüsüne gelir. Etkinlik Bağlamını öldürecek belirli olaylar (yönlendirme gibi) vardır. Pek çok sınıf ve yöntem bir Bağlam gerektirdiğinden, geliştiriciler bazen bir Bağlama referans alarak ve üzerine tutarak bazı kodları kaydetmeye çalışırlar. Faaliyetimizi yürütmek için yaratmamız gereken birçok nesnenin, Faaliyetin yapması gerekenleri yapmasına izin vermek için Etkinlik Yaşam Döngüsü dışında olması gerekir. Nesnelerinizden herhangi birinin bir Etkinliğe, İçeriğine veya yok edildiğinde Görünümlerinden herhangi birine referans olması durumunda, bu Etkinliği ve tüm Görünüm ağacını sızdırmışsınız demektir.
Çözümler: Etkinlikler ve Görüşler
- Her ne pahasına olursa olsun, bir Görünüme veya Etkinliğe Statik bir referans yapmaktan kaçının.
- Etkinlik Bağlamlarına yapılan tüm referanslar kısa ömürlü olmalıdır (işlevin süresi)
- Uzun ömürlü bir bağlama ihtiyacınız varsa, Uygulama Bağlamını (
getBaseContext()
veya getApplicationContext()
) kullanın. Bunlar referansları dolaylı olarak tutmaz.
- Alternatif olarak, Yapılandırma Değişikliklerini geçersiz kılarak bir Etkinliğin yok edilmesini sınırlayabilirsiniz. Ancak bu, diğer potansiyel olayların Etkinliği yok etmesini engellemez. Bunu yapabilirsiniz , ancak yine de yukarıdaki uygulamalara başvurmak isteyebilirsiniz.
Runnables: Giriş
Runnables aslında o kadar da kötü değil. Yani, olabilirler , ama gerçekten zaten tehlikeli bölgelerin çoğunu vurduk. Çalıştırılabilir, oluşturulduğu iş parçacığından bağımsız bir görev gerçekleştiren eşzamansız bir işlemdir. Çoğu çalıştırılabilir kablo UI iş parçacığından başlatılır. Özünde, bir Runnable kullanmak, biraz daha yönetilen başka bir iş parçacığı oluşturmaktır. Runnable'ı standart bir sınıf gibi sınıflandırır ve yukarıdaki yönergeleri izlerseniz, birkaç sorunla karşılaşmanız gerekir. Gerçek şu ki, birçok geliştirici bunu yapmıyor.
Kolaylık, okunabilirlik ve mantıksal program akışı dışında, birçok geliştirici Anonim İç Sınıfları kullanarak yukarıda oluşturduğunuz örnek gibi Runnable'larını tanımlar. Bu, yukarıda yazdığınız gibi bir örnekle sonuçlanır. Anonim İç Sınıf temelde ayrık bir İç Sınıftır. Tamamen yeni bir tanım oluşturmak ve sadece uygun yöntemleri geçersiz kılmak zorunda değilsiniz. Diğer tüm açılardan, bir İç Sınıftır, yani kabına örtük bir referans tutar.
Çalıştırılabilirler ve Etkinlikler / Görünümler
Yaşasın! Bu bölüm kısa olabilir! Runnable'ların mevcut iş parçacığının dışında çalışması nedeniyle, bunlarla ilgili tehlike uzun süreli asenkron işlemlere neden olur. Runnable bir Etkinlik veya Görünümde Anonim İç Sınıf VEYA iç içe İç Sınıf olarak tanımlanmışsa, bazı çok ciddi tehlikeler vardır. Daha önce belirtildiği gibi, bu Bunun nedeni vardır kabını kim olduğunu bilmek. Yön değişikliğini (veya sistem ölümünü) girin. Şimdi ne olduğunu anlamak için önceki bölümlere bakın. Evet, örneğiniz oldukça tehlikelidir.
Çözümler: Çalıştırılabilirler
- Kodunuzun mantığını bozmazsa Runnable'ı genişletmeyi deneyin.
- İç içe geçmiş sınıflar gerekiyorsa, genişletilmiş Runnable'ları statik yapmak için elinizden geleni yapın.
- Anonim Runnable'ları kullanmanız gerekiyorsa, bunları herhangi bir olan bir Etkinlik veya Görünüm için uzun ömürlü bir referansı olan nesnede .
- Birçok Runnable, AsyncTasks kadar kolay olabilirdi. Varsayılan olarak VM tarafından yönetilen AsyncTask kullanmayı düşünün.
Son Soruyu Cevaplama
Şimdi doğrudan olmayan soruları cevaplamak için bu yazının diğer bölümleri tarafından ele . "Bir iç sınıftaki bir nesne dış sınıfından ne zaman daha uzun süre hayatta kalabilir?" Bunu yapmadan önce, yeniden vurgulayayım: Etkinlikler'de bu konuda endişelenmeye haklı olmanıza rağmen, her yerde bir sızıntıya neden olabilir. Sadece göstermek için basit bir örnek vereceğim (Etkinlik kullanmadan).
Aşağıda temel bir fabrikaya (kod eksik) ortak bir örnek verilmiştir.
public class LeakFactory
{//Just so that we have some data to leak
int myID = 0;
// Necessary because our Leak class is an Inner class
public Leak createLeak()
{
return new Leak();
}
// Mass Manufactured Leak class
public class Leak
{//Again for a little data.
int size = 1;
}
}
Bu yaygın bir örnek değil, gösterilebilecek kadar basit. Burada anahtar yapıcı ...
public class SwissCheese
{//Can't have swiss cheese without some holes
public Leak[] myHoles;
public SwissCheese()
{//Gotta have a Factory to make my holes
LeakFactory _holeDriller = new LeakFactory()
// Now, let's get the holes and store them.
myHoles = new Leak[1000];
for (int i = 0; i++; i<1000)
{//Store them in the class member
myHoles[i] = _holeDriller.createLeak();
}
// Yay! We're done!
// Buh-bye LeakFactory. I don't need you anymore...
}
}
Şimdi, Sızıntılarımız var, ama Fabrika yok. Fabrikayı serbest bırakmamıza rağmen, bellekte kalacak çünkü her bir Sızıntı'nın bir referansı var. Dış sınıfın veri içermesi bile önemli değil. Bu, birinin düşündüğünden çok daha sık olur. Yaratıcıya ihtiyacımız yok, sadece yaratımlarına. Bu yüzden geçici olarak bir tane yaratıyoruz, ancak kreasyonları süresiz olarak kullanıyoruz.
Yapıcıyı biraz değiştirdiğimizde ne olacağını hayal edin.
public class SwissCheese
{//Can't have swiss cheese without some holes
public Leak[] myHoles;
public SwissCheese()
{//Now, let's get the holes and store them.
myHoles = new Leak[1000];
for (int i = 0; i++; i<1000)
{//WOW! I don't even have to create a Factory...
// This is SOOOO much prettier....
myHoles[i] = new LeakFactory().createLeak();
}
}
}
Şimdi, bu yeni LeakFactories'in her biri sızdırılmış durumda. Bunun hakkında ne düşünüyorsun? Bunlar, bir iç sınıfın herhangi bir türden bir dış sınıftan nasıl daha uzun yaşayabileceğine dair çok yaygın iki örnektir. Bu dış sınıf bir Aktivite olsaydı, ne kadar kötü olacağını hayal edin.
Sonuç
Bunlar, bu nesneleri uygun olmayan şekilde kullanmanın bilinen tehlikelerini listeler. Genel olarak, bu yazı sorularınızın çoğunu kapsamalıdır, ancak bunun bir loooong yazısı olduğunu anlıyorum, bu yüzden açıklığa ihtiyacınız varsa, bana bildirin. Yukarıdaki uygulamaları takip ettiğiniz sürece, sızıntı konusunda çok az endişe duyacaksınız.