安卓常見的內(nèi)存泄漏

先解釋下內(nèi)存泄露內(nèi)存溢出,這兩個比較容易混淆的概念:

內(nèi)存泄露程序在向系統(tǒng)申請分配內(nèi)存空間后(new)修陡,在使用完畢后未釋放邀桑。結(jié)果導致一直占據(jù)該內(nèi)存單元,我們和程序都無法再使用該內(nèi)存單元工窍,直到程序結(jié)束割卖,這是內(nèi)存泄露。比如當一個對象已經(jīng)不需要再使用了患雏,本該被回收時鹏溯,而另外一個正在使用的對象持有它的引用從而導致它不能被回收,這就導致本該被回收的對象不能被回收而停留在堆內(nèi)存中淹仑,內(nèi)存泄漏就產(chǎn)生了丙挽。

內(nèi)存溢出程序向系統(tǒng)申請的內(nèi)存空間超出了系統(tǒng)能給的。比如加載一張大圖片時候攻人,需要的內(nèi)存超過系統(tǒng)分配的最大內(nèi)存取试,導致程序崩潰;

大量的內(nèi)存泄露會導致內(nèi)存溢出(oom)怀吻。

1. observer 我們在使用監(jiān)聽器的時候瞬浓,往往是addxxxlistener,但是當我們不需要的時候蓬坡,忘記removexxxlistener猿棉,就容易內(nèi)存leak。

廣播沒有unregisterrecevier

2.對于使用了BraodcastReceiver屑咳,ContentObserver萨赁,F(xiàn)ile,Cursor兆龙,Stream杖爽,Bitmap等資源的使用,應(yīng)該在Activity銷毀時及時關(guān)閉或者注銷,否則這些資源將不會被回收慰安,造成內(nèi)存泄漏

3.Handler造成的內(nèi)存泄漏

Handler的使用造成的內(nèi)存泄漏問題應(yīng)該說最為常見了腋寨,平時在處理網(wǎng)絡(luò)任務(wù)或者封裝一些請求回調(diào)等api都應(yīng)該會借助Handler來處理,對于Handler的使用代碼編寫一不規(guī)范即有可能造成內(nèi)存泄漏化焕,如下示例:

public class MainActivity extends AppCompatActivity {

private Handler mHandler = new Handler() {

@Override

public void handleMessage(Message msg) {

//...

}

};

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

loadData();

}

private void loadData(){

//...request

Message message = Message.obtain();

mHandler.sendMessage(message);

}

}

這種創(chuàng)建Handler的方式會造成內(nèi)存泄漏萄窜,由于mHandler是Handler的非靜態(tài)匿名內(nèi)部類的實例,所以它持有外部類Activity的引用撒桨,我們知道消息隊列是在一個Looper線程中不斷輪詢處理消息查刻,那么當這個Activity退出時消息隊列中還有未處理的消息或者正在處理消息,而消息隊列中的Message持有mHandler實例的引用凤类,mHandler又持有Activity的引用穗泵,所以導致該Activity的內(nèi)存資源無法及時回收,引發(fā)內(nèi)存泄漏谜疤,所以另外一種做法為:

public class MainActivity extends AppCompatActivity {

private MyHandler mHandler = new MyHandler(this);

private TextView mTextView ;

private static class MyHandler extends Handler {

private WeakReference reference;

public MyHandler(Context context) {

reference = new WeakReference<>(context);

}

@Override

public void handleMessage(Message msg) {

MainActivity activity = (MainActivity) reference.get();

if(activity != null){

activity.mTextView.setText("");

}

}

}

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mTextView = (TextView)findViewById(R.id.textview);

loadData();

}

private void loadData() {

//...request

Message message = Message.obtain();

mHandler.sendMessage(message);

}

}

創(chuàng)建一個靜態(tài)Handler內(nèi)部類火欧,然后對Handler持有的對象使用弱引用,這樣在回收時也可以回收Handler持有的對象茎截,這樣雖然避免了Activity泄漏,不過Looper線程的消息隊列中還是可能會有待處理的消息赶盔,所以我們在Activity的Destroy時或者Stop時應(yīng)該移除消息隊列中的消息企锌,更準確的做法如下:

public class MainActivity extends AppCompatActivity {

private MyHandler mHandler = new MyHandler(this);

private TextView mTextView ;

private static class MyHandler extends Handler {

private WeakReference reference;

public MyHandler(Context context) {

reference = new WeakReference<>(context);

}

@Override

public void handleMessage(Message msg) {

MainActivity activity = (MainActivity) reference.get();

if(activity != null){

activity.mTextView.setText("");

}

}

}

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mTextView = (TextView)findViewById(R.id.textview);

loadData();

}

private void loadData() {

//...request

Message message = Message.obtain();

mHandler.sendMessage(message);

}

@Override

protected void onDestroy() {

super.onDestroy();

mHandler.removeCallbacksAndMessages(null);

}

}

使用mHandler.removeCallbacksAndMessages(null);是移除消息隊列中所有消息和所有的Runnable。當然也可以使用mHandler.removeCallbacks();或mHandler.removeMessages();來移除指定的Runnable和Message于未。

4.單例

因為單例的靜態(tài)特性使得單例的生命周期和應(yīng)用的生命周期一樣長撕攒,這就說明了如果一個對象已經(jīng)不需要使用了,而單例對象還持有該對象的引用烘浦,那么這個對象將不能被正扯镀海回收,這就導致了內(nèi)存泄漏闷叉。

5.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末擦俐,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子握侧,更是在濱河造成了極大的恐慌蚯瞧,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件品擎,死亡現(xiàn)場離奇詭異埋合,居然都是意外死亡,警方通過查閱死者的電腦和手機萄传,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門甚颂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事振诬〔渌” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵贷揽,是天一觀的道長棠笑。 經(jīng)常有香客問我,道長禽绪,這世上最難降的妖魔是什么蓖救? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮印屁,結(jié)果婚禮上循捺,老公的妹妹穿的比我還像新娘。我一直安慰自己雄人,他們只是感情好从橘,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著础钠,像睡著了一般恰力。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上旗吁,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天踩萎,我揣著相機與錄音,去河邊找鬼很钓。 笑死香府,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的码倦。 我是一名探鬼主播企孩,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼袁稽!你這毒婦竟也來了勿璃?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤运提,失蹤者是張志新(化名)和其女友劉穎蝗柔,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體民泵,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡癣丧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了栈妆。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胁编。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡厢钧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嬉橙,到底是詐尸還是另有隱情早直,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布市框,位于F島的核電站霞扬,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏枫振。R本人自食惡果不足惜喻圃,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望粪滤。 院中可真熱鬧斧拍,春花似錦、人聲如沸杖小。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽予权。三九已至昂勉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間扫腺,已是汗流浹背硼啤。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留斧账,地道東北人。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓煞肾,卻偏偏與公主長得像咧织,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子籍救,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容