Java內(nèi)存泄露知識點

java的內(nèi)存分配

  • 靜態(tài)存儲區(qū): 編譯時已經(jīng)分配好內(nèi)存,在程序整個運行期間都存在,主要存放靜態(tài)數(shù)據(jù)和常量
  • 棧區(qū):當方法執(zhí)行時,會在棧區(qū)中創(chuàng)建方法內(nèi)部的局部變量,方法結(jié)束后自動釋放內(nèi)存
  • 堆區(qū):通常用來存放new出來的對象,由java垃圾回收器回收

內(nèi)存泄露分析

永遠的singleton
由于單例的靜態(tài)特性,使得它的生命周期和應(yīng)用的生命周期一樣長。當我們使用單例的時候,要注意它內(nèi)部持有的引用,如Activity(導致Activity不能被回收)

public class Singleton{
    private static Singleton singleton;
    private Context context;
    
    private Singleton(Context context){
        this.context=context;
    }
    
    public static Singleton getInstance(Context context){
        if(singleton==null){
            singletoon=new Singleton(context);
        }
        return singleton;
    }
}

如果該單例中需要一個Context,那么確保不要持有Activity的引用,可以使用Application提供的Context。

讓人心塞的handler
handler一般作為Acvivity的非靜態(tài)內(nèi)部類被創(chuàng)建,那么他就持有了Activity的引用,當我們發(fā)送一個延遲消息的時候,Message持有hanlder的引用,而handler持有Activity的引用,所以,當我們主動調(diào)用finish()方法的時候,Activity并不會被回收。而如果我們在Activity中需要引用外部的非static對象,應(yīng)該通過弱引用傳入。

public class DemoActivity extends Activity{
    private static final class MyHandler extends Handler{
        private final WeakReference<DemoActivity> mActivity;
        
        public MyHandler(DemoActivity activity){
            this.mActivity=new WeakReference<DemoActivity>(activity);
        }
        @override
        public void handleMessage(Message msg){
            DemoActivity activity=mActivity.get();
            if(activity!=null){
                //do sonmething
            }
        }
    }
    
    private final MyHandler handler=new MyHandler(this);
}

靜態(tài)內(nèi)部類不會持有外部類的引用,推薦使用靜態(tài)內(nèi)部類+弱引用,每次使用時注意進行非空判斷。

同時,在Activity被銷毀時,可以清空MessageQueue中的消息。

匿名內(nèi)部類/非靜態(tài)內(nèi)部類
一般在Activity、Fragment或者View中創(chuàng)建內(nèi)部類,如果是非靜態(tài)內(nèi)部類,則會持有外部類的引用。
而如果這個內(nèi)部類被異步線程所引用,則很可能導致內(nèi)存泄露。

public class DemoActivity extends Activity{
    private static TestInnerBad testInnerBad=null;
    
    class TestInnerBad{}
    
    @override
    public void onCreate(Bundle bundle){
        
        if(testInnerBad==null){
            testInnerBad=new TestInnerBad();  //內(nèi)存泄露
        }
        Runnable r1=new Runnable(){   //可能內(nèi)存泄露
            @override
            public void run(){
                    
            }
        }
        Runnable r2=new MyRunnable();
    }
    
    private static class MyRunnable implements Runnable{
        @override
        public void run(){}
    }
}

TestInnerBad是DemoActivity的內(nèi)部類,持有他的引用,而它又被聲明為static,那么他的生命周期就和App一樣,那么肯定是造成了DemoActivity無法被正確的回收。對靜態(tài)類的正確處理方法是---單獨抽取出來封裝成一個單例。

r1是DemoActivity的匿名內(nèi)部類,他持有DemoActivity的引用,而如果r1被傳入到一個異步線程中,則很可能造成內(nèi)存泄露。

集合對象的清除
如果這個集合是static,那么該集合會一直持有傳入對象的引用,一般要在Activity、Fragment被銷毀時將集合清空。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • 內(nèi)存管理的目的就是讓我們在開發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問題。內(nèi)存泄漏大家都不陌生了,簡單粗俗的講,...
    宇宙只有巴掌大閱讀 2,391評論 0 12
  • Android 內(nèi)存泄漏總結(jié) 內(nèi)存管理的目的就是讓我們在開發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問題。內(nèi)存泄漏...
    _痞子閱讀 1,650評論 0 8
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,829評論 25 708
  • 一、基礎(chǔ)知識 1、什么是內(nèi)存泄露 java中的內(nèi)存泄露是指一個無用對象持續(xù)占有內(nèi)存或無用對象的內(nèi)存得不到及時的釋放...
    LiveMoment閱讀 4,439評論 0 20
  • 上一章 2.突如其來的老大 事情還要從我媽在全申鑫酒店里遇上的一件不可思議的事情說起。 全申鑫大酒店是陸家嘴一帶最...
    舞風眠雨閱讀 472評論 0 3