android编译非静态内部类,Android 非静态内部类/匿名类引起的内存泄漏
一、概述
讓我們先來(lái)回顧一下android內(nèi)存泄漏的相關(guān)概念:
內(nèi)存溢出:android系統(tǒng)會(huì)給每個(gè)安卓程序分配一定的內(nèi)存,當(dāng)程序所使用的內(nèi)存超過(guò)最大值就會(huì)造成內(nèi)存溢出,就是常說(shuō)的OOM
內(nèi)存泄漏:簡(jiǎn)單來(lái)說(shuō)就是你new了一個(gè)對(duì)象,這個(gè)對(duì)象是要消耗內(nèi)存的,然后jvm會(huì)對(duì)沒(méi)有引用的對(duì)象進(jìn)行回收釋放內(nèi)存,如果一個(gè)對(duì)象已經(jīng)沒(méi)有引用了,但是jvm沒(méi)有回收這個(gè)對(duì)象,就會(huì)造成內(nèi)存泄漏,多次內(nèi)存泄漏到最后就會(huì)變成內(nèi)存溢出。
二、內(nèi)存泄漏
常見(jiàn)的內(nèi)存泄漏有很多種:
1. 非靜態(tài)內(nèi)部類/匿名內(nèi)部類的靜態(tài)實(shí)例容易造成內(nèi)存泄漏
2. 單例模式導(dǎo)致的內(nèi)存泄漏
3. 對(duì)該解注冊(cè)、注銷、清空的對(duì)象沒(méi)有及時(shí)做這樣操作導(dǎo)致的,比如說(shuō)廣播、服務(wù)、io流等等。(其實(shí)我個(gè)人覺(jué)得這一條的最終原因還是第一條,因?yàn)檎f(shuō)到底還是引用沒(méi)有釋放使jvm沒(méi)有不能回收)
三、非靜態(tài)內(nèi)部類/匿名內(nèi)部類的靜態(tài)實(shí)例容易造成內(nèi)存泄漏
綜上所述,我們來(lái)重點(diǎn)理解一下非靜態(tài)內(nèi)部類/匿名內(nèi)部類的靜態(tài)實(shí)例容易造成內(nèi)存泄漏,因?yàn)橐郧白髡咴诹私鈇ndroid內(nèi)存泄漏方面的知識(shí)的時(shí)候,對(duì)于網(wǎng)上帖子整理出來(lái)的常見(jiàn)內(nèi)存泄漏的例子,我會(huì)更多的嘗試把它們記住。。因?yàn)楦静焕斫馐菫槭裁磿?huì)造成內(nèi)存泄漏,所以效率非常低,而且真正碰到了的時(shí)候也發(fā)現(xiàn)不了。
java內(nèi)部類分為四種
靜態(tài)內(nèi)部類
靜態(tài)匿名內(nèi)部類
非靜態(tài)內(nèi)部類
非靜態(tài)內(nèi)部匿名類
/**
* 人類
*/
public class Human {
private static int age = 1;// 年齡
private String name;// 姓名
// 內(nèi)部類
public class Man{}
// 靜態(tài)內(nèi)部類
public static class WoMan{}
public void setMan(Man man){}
public void setWoMan(WoMan woMan){}
public void test(){
Human human = new Human();
// 向human對(duì)象setMan方法中傳入一個(gè)匿名的Man對(duì)象
human.setMan(new Man());
// 這種方式和上面的方式其實(shí)是一樣的,大家應(yīng)該可以看的出來(lái)
// 上面的方式就是我們常用的控件事件監(jiān)聽(tīng)
Man man = new Man();
human.setMan(man);
// 向human對(duì)象setWoMan方法中傳入一個(gè)匿名的Man對(duì)象
human.setWoMan(new WoMan());
}
}
你們可能會(huì)問(wèn),靜態(tài)內(nèi)部類和非靜態(tài)內(nèi)部類到底有什么關(guān)系呢?靜態(tài)變量大家都會(huì)用吧:
private static int age = 1;// 年齡
static的東西就代表是直接丟內(nèi)存的,就是我們常說(shuō)的緩存,順便說(shuō)一句,程序Exception的時(shí)候是會(huì)清空內(nèi)存的。
拿上面的例子來(lái)說(shuō),Human類有一個(gè)靜態(tài)的變量age,也就是說(shuō)age是所有Human對(duì)象所共享的,換句話說(shuō)是整個(gè)人類都有相同的年齡。而類成員變量name就只屬于單個(gè)Human對(duì)象,每個(gè)人有屬于他自己的名字,并不是共享的。通過(guò)這個(gè)例子好好理解一下static這個(gè)修飾符的概念,后面還會(huì)提到。
在Java中,非靜態(tài)內(nèi)部類/匿名類會(huì)隱式的持有外部類的引用,像這段代碼:
human.setMan(new Man());
Man man = new Man();
human.setMan(man);
這樣寫是沒(méi)有問(wèn)題的,內(nèi)部類隱式持有外部引用,生命周期是相同的,不會(huì)造成內(nèi)存泄漏,但是我們來(lái)修改一下:
// 在Human里面定義一個(gè)static的Man變量
private static Man whiteMan;// 白人
然后:
whiteMan = new Man();
在test()方法中初始化這個(gè)whiteMan,此時(shí),whiteMan是持有持有外部類Human的隱式引用,但是whiteMan是static的,static修飾的變量是放在內(nèi)存中,生命周期是超過(guò)Human的,此時(shí)就已經(jīng)發(fā)生了內(nèi)存泄漏,類似的android中常見(jiàn)的內(nèi)存泄漏:
public class MyActivity extends AppCompatActivity {
private static Context context;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
context = this;
}
}
這是最基本常見(jiàn)的內(nèi)存泄漏,通過(guò)我們那面的Human類的例子來(lái)理解一下這個(gè)內(nèi)存泄漏,首先Activity就相當(dāng)于Human類,然后static修飾的Context就相當(dāng)于whiteMan,這個(gè)Context是持有Activity的引用的,它的生命周期是超過(guò)Activity的,并且這個(gè)本該被回收的activty由于它還一直存在著,這就導(dǎo)致了內(nèi)存泄漏。
解決辦法:把上述例子中的Man加上static修飾,如同WoMan。
用靜態(tài)內(nèi)部類/匿名類替換非靜態(tài)內(nèi)部類/匿名類,因?yàn)殪o態(tài)內(nèi)部類/匿名類不會(huì)隱式的持有外部類引用,外部類會(huì)以正常的方式回收。
四、總結(jié)
關(guān)鍵詞:static,原理:存放在內(nèi)存中。如果像前面的Human類中那樣的話,一個(gè)靜態(tài)的變量是屬于所有Human類的實(shí)例,而不是屬于單個(gè)實(shí)例。
總結(jié)
以上是生活随笔為你收集整理的android编译非静态内部类,Android 非静态内部类/匿名类引起的内存泄漏的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: android关键应用程序,安卓开发:A
- 下一篇: android.os.build修改,A