国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

內(nèi)存泄漏優(yōu)化

fanux / 1525人閱讀

摘要:內(nèi)存泄漏造成什么影響它是造成應(yīng)用程序的主要原因之一。造成的內(nèi)存泄漏早時(shí)期的時(shí)候處理耗時(shí)操作多數(shù)都是采用的方式,后來逐步被取代,直到現(xiàn)在采用的方式來處理異步。

目錄介紹:

01.什么是內(nèi)存泄漏

02.內(nèi)存泄漏造成什么影響

03.內(nèi)存泄漏檢測的工具有哪些

04.關(guān)于Leakcanary使用介紹

05.錯(cuò)誤使用單例造成的內(nèi)存泄漏

06.Handler使用不當(dāng)造成內(nèi)存泄漏

07.Thread未關(guān)閉造成內(nèi)容泄漏

08.錯(cuò)誤使用靜態(tài)變量導(dǎo)致引用后無法銷毀

09.AsyncTask造成的內(nèi)存泄漏

10.非靜態(tài)內(nèi)部類創(chuàng)建靜態(tài)實(shí)例造成內(nèi)存泄漏

11.不需要用的監(jiān)聽未移除會(huì)發(fā)生內(nèi)存泄露

12.資源未關(guān)閉造成的內(nèi)存泄漏

13.廣播注冊之后沒有被銷毀

14.錯(cuò)誤使用context上下文引起內(nèi)存泄漏

15.靜態(tài)集合使用不當(dāng)導(dǎo)致的內(nèi)存泄漏

16.動(dòng)畫資源未釋放導(dǎo)致內(nèi)存泄漏

17.系統(tǒng)bug之InputMethodManager導(dǎo)致內(nèi)存泄漏

好消息

博客筆記大匯總【16年3月到至今】,包括Java基礎(chǔ)及深入知識(shí)點(diǎn),Android技術(shù)博客,Python學(xué)習(xí)筆記等等,還包括平時(shí)開發(fā)中遇到的bug匯總,當(dāng)然也在工作之余收集了大量的面試題,長期更新維護(hù)并且修正,持續(xù)完善……開源的文件是markdown格式的!同時(shí)也開源了生活博客,從12年起,積累共計(jì)N篇[近100萬字,陸續(xù)搬到網(wǎng)上],轉(zhuǎn)載請注明出處,謝謝!

鏈接地址:https://github.com/yangchong2...

如果覺得好,可以star一下,謝謝!當(dāng)然也歡迎提出建議,萬事起于忽微,量變引起質(zhì)變!

01.什么是內(nèi)存泄漏

一些對象有著有限的聲明周期,當(dāng)這些對象所要做的事情完成了,我們希望它們會(huì)被垃圾回收器回收掉。但是如果有一系列對這個(gè)對象的引用存在,那么在我們期待這個(gè)對象生命周期結(jié)束時(shí)被垃圾回收器回收的時(shí)候,它是不會(huì)被回收的。它還會(huì)占用內(nèi)存,這就造成了內(nèi)存泄露。持續(xù)累加,內(nèi)存很快被耗盡。

比如:當(dāng)Activity的onDestroy()方法被調(diào)用后,Activity以及它涉及到的View和相關(guān)的Bitmap都應(yīng)該被回收掉。但是,如果有一個(gè)后臺(tái)線程持有這個(gè)Activity的引用,那么該Activity所占用的內(nèi)存就不能被回收,這最終將會(huì)導(dǎo)致內(nèi)存耗盡引發(fā)OOM而讓應(yīng)用crash掉。

02.內(nèi)存泄漏造成什么影響

它是造成應(yīng)用程序OOM的主要原因之一。由于android系統(tǒng)為每個(gè)應(yīng)用程序分配的內(nèi)存有限,當(dāng)一個(gè)應(yīng)用中產(chǎn)生的內(nèi)存泄漏比較多時(shí),就難免會(huì)導(dǎo)致應(yīng)用所需要的內(nèi)存超過這個(gè)系統(tǒng)分配的內(nèi)存限額,這就

03.內(nèi)存泄漏檢測的工具有哪些

最常見的是:Leakcanary

04.關(guān)于Leakcanary使用介紹

leakCanary是Square開源框架,是一個(gè)Android和Java的內(nèi)存泄露檢測庫,如果檢測到某個(gè) activity 有內(nèi)存泄露,LeakCanary 就是自動(dòng)地顯示一個(gè)通知,所以可以把它理解為傻瓜式的內(nèi)存泄露檢測工具。通過它可以大幅度減少開發(fā)中遇到的oom問題,大大提高APP的質(zhì)量。

關(guān)于如何配置,這個(gè)就不說呢,網(wǎng)上有步驟

05.錯(cuò)誤使用單例造成的內(nèi)存泄漏

在平時(shí)開發(fā)中單例設(shè)計(jì)模式是我們經(jīng)常使用的一種設(shè)計(jì)模式,而在開發(fā)中單例經(jīng)常需要持有Context對象,如果持有的Context對象生命周期與單例生命周期更短時(shí),或?qū)е翪ontext無法被釋放回收,則有可能造成內(nèi)存泄漏,錯(cuò)誤寫法如下:

問題引起內(nèi)存泄漏代碼

public class LoginManager {
    private static LoginManager mInstance;
    private Context mContext;

    private LoginManager(Context context) {
        this.mContext = context;          
        //修改代碼:this.mContext = context.getApplicationContext();
    }

    public static LoginManager getInstance(Context context) {
        if (mInstance == null) {
            synchronized (LoginManager.class) {
                if (mInstance == null) {
                    mInstance = new LoginManager(context);
                }
            }
        }
        return mInstance;
    }

    public void dealData() {}
}

使用場景

在一個(gè)Activity中調(diào)用的,然后關(guān)閉該Activity則會(huì)出現(xiàn)內(nèi)存泄漏。

LoginManager.getInstance(this).dealData();

看看報(bào)錯(cuò)截圖

解決辦法:

要保證Context和AppLication的生命周期一樣,修改后代碼如下:

this.mContext = context.getApplicationContext();

1、如果此時(shí)傳入的是 Application 的 Context,因?yàn)?Application 的生命周期就是整個(gè)應(yīng)用的生命周期,所以這將沒有任何問題。

2、如果此時(shí)傳入的是 Activity 的 Context,當(dāng)這個(gè) Context 所對應(yīng)的 Activity 退出時(shí),由于該 Context 的引用被單例對象所持有,其生命周期等于整個(gè)應(yīng)用程序的生命周期,所以當(dāng)前 Activity 退出時(shí)它的內(nèi)存并不會(huì)被回收,這就造成泄漏了。

06.Handler使用不當(dāng)造成內(nèi)存泄漏

handler是工作線程與UI線程之間通訊的橋梁,只是現(xiàn)在大量開源框架對其進(jìn)行了封裝,我們這里模擬一種常見使用方式來模擬內(nèi)存泄漏情形。

解決Handler內(nèi)存泄露主要2點(diǎn)

有延時(shí)消息,要在Activity銷毀的時(shí)候移除Messages

匿名內(nèi)部類導(dǎo)致的泄露改為匿名靜態(tài)內(nèi)部類,并且對上下文或者Activity使用弱引用。

問題代碼

public class MainActivity extends AppCompatActivity {
    private Handler mHandler = new Handler();
    private TextView mTextView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = (TextView) findViewById(R.id.text);        //模擬內(nèi)存泄露
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                mTextView.setText("yangchong");
            }
        }, 2000);
    }
}

造成內(nèi)存泄漏原因分析

上述代碼通過內(nèi)部類的方式創(chuàng)建mHandler對象,此時(shí)mHandler會(huì)隱式地持有一個(gè)外部類對象引用這里就是MainActivity,當(dāng)執(zhí)行postDelayed方法時(shí),該方法會(huì)將你的Handler裝入一個(gè)Message,并把這條Message推到MessageQueue中,MessageQueue是在一個(gè)Looper線程中不斷輪詢處理消息,那么當(dāng)這個(gè)Activity退出時(shí)消息隊(duì)列中還有未處理的消息或者正在處理消息,而消息隊(duì)列中的Message持有mHandler實(shí)例的引用,mHandler又持有Activity的引用,所以導(dǎo)致該Activity的內(nèi)存資源無法及時(shí)回收,引發(fā)內(nèi)存泄漏。

查看報(bào)錯(cuò)結(jié)果如下:

解決方案

第一種解決辦法

要想避免Handler引起內(nèi)存泄漏問題,需要我們在Activity關(guān)閉退出的時(shí)候的移除消息隊(duì)列中所有消息和所有的Runnable。

上述代碼只需在onDestroy()函數(shù)中調(diào)用mHandler.removeCallbacksAndMessages(null);就行了。

@Override
protected void onDestroy() {
    super.onDestroy();
    if(handler!=null){
        handler.removeCallbacksAndMessages(null);
        handler = null;
    }
}

第二種解決方案

使用弱引用解決handler內(nèi)存泄漏問題,關(guān)于代碼案例,可以參考我的開源項(xiàng)目:https://github.com/yangchong2...

//自定義handler
public static class HandlerHolder extends Handler {
    WeakReference mListenerWeakReference;
    /**
     * @param listener 收到消息回調(diào)接口
     */
    HandlerHolder(OnReceiveMessageListener listener) {
        mListenerWeakReference = new WeakReference<>(listener);
    }

    @Override
    public void handleMessage(Message msg) {
        if (mListenerWeakReference!=null && mListenerWeakReference.get()!=null){
            mListenerWeakReference.get().handlerMessage(msg);
        }
    }
}

//創(chuàng)建handler對象
private HandlerHolder handler = new HandlerHolder(new OnReceiveMessageListener() {
    @Override
    public void handlerMessage(Message msg) {
        switch (msg.what){
            case 1:
                TextView textView1 = (TextView) msg.obj;
                showBottomInAnimation(textView1);
                break;
            case 2:
                TextView textView2 = (TextView) msg.obj;
                showBottomOutAnimation(textView2);
                break;
        }
    }
});

//發(fā)送消息
Message message = new Message();
message.what = 1;
message.obj = textView;
handler.sendMessageDelayed(message,time);


即推薦使用靜態(tài)內(nèi)部類 + WeakReference 這種方式。每次使用前注意判空。

07.Thread未關(guān)閉造成內(nèi)容泄漏

當(dāng)在開啟一個(gè)子線程用于執(zhí)行一個(gè)耗時(shí)操作后,此時(shí)如果改變配置(例如橫豎屏切換)導(dǎo)致了Activity重新創(chuàng)建,一般來說舊Activity就將交給GC進(jìn)行回收。但如果創(chuàng)建的線程被聲明為非靜態(tài)內(nèi)部類或者匿名類,那么線程會(huì)保持有舊Activity的隱式引用。當(dāng)線程的run()方法還沒有執(zhí)行結(jié)束時(shí),線程是不會(huì)被銷毀的,因此導(dǎo)致所引用的舊的Activity也不會(huì)被銷毀,并且與該Activity相關(guān)的所有資源文件也不會(huì)被回收,因此造成嚴(yán)重的內(nèi)存泄露。

因此總結(jié)來看, 線程產(chǎn)生內(nèi)存泄露的主要原因有兩點(diǎn):

1.線程生命周期的不可控。Activity中的Thread和AsyncTask并不會(huì)因?yàn)锳ctivity銷毀而銷毀,Thread會(huì)一直等到run()執(zhí)行結(jié)束才會(huì)停止,AsyncTask的doInBackground()方法同理

2.非靜態(tài)的內(nèi)部類和匿名類會(huì)隱式地持有一個(gè)外部類的引用

例如如下代碼,在onCreate()方法中啟動(dòng)一個(gè)線程,并用一個(gè)靜態(tài)變量threadIndex標(biāo)記當(dāng)前創(chuàng)建的是第幾個(gè)線程

public class ThreadActivity extends AppCompatActivity {

    private final String TAG = "ThreadActivity";

    private static int threadIndex;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_thread);
        threadIndex++;
        new Thread(new Runnable() {
            @Override
            public void run() {
                int j = threadIndex;
                while (true) {
                    Log.e(TAG, "Hi--" + j);
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

}

旋轉(zhuǎn)幾次屏幕,可以看到輸出結(jié)果為:

04-04 08:15:16.373 23731-23911/com.yc.leakdemo E/ThreadActivity: Hi--2
04-04 08:15:16.374 23731-26132/com.yc.leakdemo E/ThreadActivity: Hi--4
04-04 08:15:16.374 23731-23970/com.yc.leakdemo E/ThreadActivity: Hi--3
04-04 08:15:16.374 23731-23820/com.yc.leakdemo E/ThreadActivity: Hi--1
04-04 08:15:16.852 23731-26202/com.yc.leakdemo E/ThreadActivity: Hi--5
04-04 08:15:18.374 23731-23911/com.yc.leakdemo E/ThreadActivity: Hi--2
04-04 08:15:18.374 23731-26132/com.yc.leakdemo E/ThreadActivity: Hi--4
04-04 08:15:18.376 23731-23970/com.yc.leakdemo E/ThreadActivity: Hi--3
04-04 08:15:18.376 23731-23820/com.yc.leakdemo E/ThreadActivity: Hi--1
04-04 08:15:18.852 23731-26202/com.yc.leakdemo E/ThreadActivity: Hi--5
...

即使創(chuàng)建了新的Activity,舊的Activity中建立的線程依然還在執(zhí)行,從而導(dǎo)致無法釋放Activity占用的內(nèi)存,從而造成嚴(yán)重的內(nèi)存泄漏。想要避免因?yàn)?Thread 造成內(nèi)存泄漏,可以在 Activity 退出后主動(dòng)停止 Thread

例如,可以為 Thread 設(shè)置一個(gè)布爾變量 threadSwitch 來控制線程的啟動(dòng)與停止

public class ThreadActivity extends AppCompatActivity {

    private final String TAG = "ThreadActivity";

    private int threadIndex;

    private boolean threadSwitch = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_thread);
        threadIndex++;
        new Thread(new Runnable() {
            @Override
            public void run() {
                int j = threadIndex;
                while (threadSwitch) {
                    Log.e(TAG, "Hi--" + j);
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        threadSwitch = false;
    }

}

如果想保持Thread繼續(xù)運(yùn)行,可以按以下步驟來:

1.將線程改為靜態(tài)內(nèi)部類,切斷Activity 對于Thread的強(qiáng)引用

2.在線程內(nèi)部采用弱引用保存Context引用,切斷Thread對于Activity 的強(qiáng)引用

public class ThreadActivity extends AppCompatActivity {

    private static final String TAG = "ThreadActivity";

    private static int threadIndex;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_thread);
        threadIndex++;
        new MyThread(this).start();
    }

    private static class MyThread extends Thread {

        private WeakReference activityWeakReference;

        MyThread(ThreadActivity threadActivity) {
            activityWeakReference = new WeakReference<>(threadActivity);
        }

        @Override
        public void run() {
            if (activityWeakReference == null) {
                return;
            }
            if (activityWeakReference.get() != null) {
                int i = threadIndex;
                while (true) {
                    Log.e(TAG, "Hi--" + i);
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

08.錯(cuò)誤使用靜態(tài)變量導(dǎo)致引用后無法銷毀

在平時(shí)開發(fā)中,有時(shí)候我們創(chuàng)建了一個(gè)工具類。比如分享工具類,十分方便多處調(diào)用,因此使用靜態(tài)方法是十分方便的。但是創(chuàng)建的對象,建議不要全局化,全局化的變量必須加上static。這樣會(huì)引起內(nèi)存泄漏!

問題代碼

使用場景

在Activity中引用后,關(guān)閉該Activity會(huì)導(dǎo)致內(nèi)存泄漏

DoShareUtil.showFullScreenShareView(PNewsContentActivity.this, title, title, shareurl, logo);

查看報(bào)錯(cuò)

解決辦法

靜態(tài)方法中,創(chuàng)建對象或變量,不要全局化,全局化后的變量或者對象會(huì)導(dǎo)致內(nèi)存泄漏;popMenuView和popMenu都不要全局化

知識(shí)延伸

非靜態(tài)內(nèi)部類,靜態(tài)實(shí)例化
public class MyActivity extends AppCompatActivity {
    //靜態(tài)成員變量
    public static InnerClass innerClass = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        innerClass = new InnerClass();
    }

    class InnerClass {
        public void doSomeThing() {}
    }
}
這里內(nèi)部類InnerClass隱式的持有外部類MyActivity的引用,而在MyActivity的onCreate方法中調(diào)用了。
這樣innerClass就會(huì)在MyActivity創(chuàng)建的時(shí)候是有了他的引用,而innerClass是靜態(tài)類型的不會(huì)被垃圾回收,
MyActivity在執(zhí)行onDestory方法的時(shí)候由于被innerClass持有了引用而無法被回收,所以這樣MyActivity就總是被innerClass持有而無法回收造成內(nèi)存泄露。

靜態(tài)變量引用不當(dāng)會(huì)導(dǎo)致內(nèi)存泄漏
靜態(tài)變量Activity和View會(huì)導(dǎo)致內(nèi)存泄漏,在下面這段代碼中對Activity的Context和TextView設(shè)置為靜態(tài)對象,從而產(chǎn)生內(nèi)存泄漏。
public class MainActivity extends AppCompatActivity {

    private static Context context;
    private static TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        context = this;
        textView = new TextView(this);
    }
}

09.AsyncTask造成的內(nèi)存泄漏

早時(shí)期的時(shí)候處理耗時(shí)操作多數(shù)都是采用Thread+Handler的方式,后來逐步被AsyncTask取代,直到現(xiàn)在采用RxJava的方式來處理異步。這里以AsyncTask為例,可能大部分人都會(huì)這樣處理一個(gè)耗時(shí)操作然后通知UI更新結(jié)果:

問題代碼

public class MainActivity extends AppCompatActivity {

    private AsyncTask asyncTask;
    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = (TextView) findViewById(R.id.text);
        testAsyncTask();
        finish();
    }

    private void testAsyncTask() {
        asyncTask = new AsyncTask() {
            @Override
            protected Integer doInBackground(Void... params) {
                int i = 0;
                //模擬耗時(shí)操作
                while (!isCancelled()) {
                    i++;
                    if (i > 1000000000) {
                        break;
                    }
                    Log.e("LeakCanary", "asyncTask---->" + i);
                }
                return i;
            }

            @Override
            protected void onPostExecute(Integer integer) {
                super.onPostExecute(integer);
                mTextView.setText(String.valueOf(integer));
            }
        };
        asyncTask.execute();
    }
}

造成內(nèi)存泄漏原因分析

在處理一個(gè)比較耗時(shí)的操作時(shí),可能還沒處理結(jié)束MainActivity就執(zhí)行了退出操作,但是此時(shí)AsyncTask依然持有對MainActivity的引用就會(huì)導(dǎo)致MainActivity無法釋放回收引發(fā)內(nèi)存泄漏

查看報(bào)錯(cuò)結(jié)果如下:

解決辦法

在使用AsyncTask時(shí),在Activity銷毀時(shí)候也應(yīng)該取消相應(yīng)的任務(wù)AsyncTask.cancel()方法,避免任務(wù)在后臺(tái)執(zhí)行浪費(fèi)資源,進(jìn)而避免內(nèi)存泄漏的發(fā)生

private void destroyAsyncTask() {
    if (asyncTask != null && !asyncTask.isCancelled()) {
        asyncTask.cancel(true);
    }
    asyncTask = null;
}

@Override
protected void onDestroy() {
    super.onDestroy();
    destroyAsyncTask();
}

10.非靜態(tài)內(nèi)部類創(chuàng)建靜態(tài)實(shí)例造成內(nèi)存泄漏

有的時(shí)候我們可能會(huì)在啟動(dòng)頻繁的Activity中,為了避免重復(fù)創(chuàng)建相同的數(shù)據(jù)資源,可能會(huì)出現(xiàn)這種寫法

問題代碼

private static TestResource mResource = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if(mResource == null){
        mResource = new TestResource();
    }
}

class TestResource {
     //里面代碼引用上下文,Activity.this會(huì)導(dǎo)致內(nèi)存泄漏
}

解決辦法

將該內(nèi)部類設(shè)為靜態(tài)內(nèi)部類或?qū)⒃搩?nèi)部類抽取出來封裝成一個(gè)單例,如果需要使用Context,請按照上面推薦的使用Application 的 Context。

分析問題

這樣就在Activity內(nèi)部創(chuàng)建了一個(gè)非靜態(tài)內(nèi)部類的單例,每次啟動(dòng)Activity時(shí)都會(huì)使用該單例的數(shù)據(jù),這樣雖然避免了資源的重復(fù)創(chuàng)建,不過這種寫法卻會(huì)造成內(nèi)存泄漏,因?yàn)榉庆o態(tài)內(nèi)部類默認(rèn)會(huì)持有外部類的引用,而該非靜態(tài)內(nèi)部類又創(chuàng)建了一個(gè)靜態(tài)的實(shí)例,該實(shí)例的生命周期和應(yīng)用的一樣長,這就導(dǎo)致了該靜態(tài)實(shí)例一直會(huì)持有該Activity的引用,導(dǎo)致Activity的內(nèi)存資源不能正常回收。

11.不需要用的監(jiān)聽未移除會(huì)發(fā)生內(nèi)存泄露

問題代碼

//add監(jiān)聽,放到集合里面
tv.getViewTreeObserver().addOnWindowFocusChangeListener(new ViewTreeObserver.OnWindowFocusChangeListener() {
    @Override
    public void onWindowFocusChanged(boolean b) {
        //監(jiān)聽view的加載,view加載出來的時(shí)候,計(jì)算他的寬高等。
    }
});

解決辦法

//計(jì)算完后,一定要移除這個(gè)監(jiān)聽
tv.getViewTreeObserver().removeOnWindowFocusChangeListener(this);

注意事項(xiàng):

tv.setOnClickListener();//監(jiān)聽執(zhí)行完回收對象,不用考慮內(nèi)存泄漏
tv.getViewTreeObserver().addOnWindowFocusChangeListene,add監(jiān)聽,放到集合里面,需要考慮內(nèi)存泄漏

12.資源未關(guān)閉造成的內(nèi)存泄漏

BroadcastReceiver,ContentObserver,F(xiàn)ileObserver,Cursor,Callback等在 Activity onDestroy 或者某類生命周期結(jié)束之后一定要 unregister 或者 close 掉,否則這個(gè) Activity 類會(huì)被 system 強(qiáng)引用,不會(huì)被內(nèi)存回收。值得注意的是,關(guān)閉的語句必須在finally中進(jìn)行關(guān)閉,否則有可能因?yàn)楫惓N搓P(guān)閉資源,致使activity泄漏。

13.廣播注冊之后沒有被銷毀

比如我們在Activity中注冊廣播,如果在Activity銷毀后不取消注冊,那么這個(gè)廣播會(huì)一直存在系統(tǒng)中,同上面所說的非靜態(tài)內(nèi)部類一樣持有Activity引用,導(dǎo)致內(nèi)存泄露。因此注冊廣播后在Activity銷毀后一定要取消注冊。

在注冊觀察則模式的時(shí)候,如果不及時(shí)取消也會(huì)造成內(nèi)存泄露。比如使用Retrofit+RxJava注冊網(wǎng)絡(luò)請求的觀察者回調(diào),同樣作為匿名內(nèi)部類持有外部引用,所以需要記得在不用或者銷毀的時(shí)候取消注冊。

public class MeAboutActivity extends BaseActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.registerReceiver(mReceiver, new IntentFilter());
    }

    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            // 接收到廣播需要做的邏輯
        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();
        this.unregisterReceiver(mReceiver);
    }
}

14.錯(cuò)誤使用context上下文引起內(nèi)存泄漏

先來看看造成內(nèi)存泄漏的代碼

通過查看Toast類的源碼可以看到,Toast類內(nèi)部的mContext指向傳入的Context。而ToastUtils中的toast變量是靜態(tài)類型的,其生命周期是與整個(gè)應(yīng)用一樣長的,從而導(dǎo)致activity得不到釋放。因此,對Context的引用不能超過它本身的生命周期。

/**
 * 吐司工具類    避免點(diǎn)擊多次導(dǎo)致吐司多次,最后導(dǎo)致Toast就長時(shí)間關(guān)閉不掉了
 * @param context       注意:這里如果傳入context會(huì)報(bào)內(nèi)存泄漏;傳遞activity..getApplicationContext()
 * @param content       吐司內(nèi)容
 */
private static Toast toast;
@SuppressLint("ShowToast")
public static void showToast(Context context, String content) {
    if (toast == null) {
        toast = Toast.makeText(context , content, Toast.LENGTH_SHORT);
    } else {
        toast.setText(content);
    }
    toast.show();
}

解決辦法

是改為使用 ApplicationContext即可,因?yàn)锳pplicationContext會(huì)隨著應(yīng)用的存在而存在,而不依賴于Activity的生命周期

15.靜態(tài)集合使用不當(dāng)導(dǎo)致的內(nèi)存泄漏

有時(shí)候我們需要把一些對象加入到集合容器(例如ArrayList)中,當(dāng)不再需要當(dāng)中某些對象時(shí),如果不把該對象的引用從集合中清理掉,也會(huì)使得GC無法回收該對象。如果集合是static類型的話,那內(nèi)存泄漏情況就會(huì)更為嚴(yán)重。因此,當(dāng)不再需要某對象時(shí),需要主動(dòng)將之從集合中移除。

16.動(dòng)畫資源未釋放導(dǎo)致內(nèi)存泄漏

問題代碼

public class LeakActivity extends AppCompatActivity {

    private TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_leak);
        textView = (TextView)findViewById(R.id.text_view);
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(textView,"rotation",0,360);
        objectAnimator.setRepeatCount(ValueAnimator.INFINITE);
        objectAnimator.start();
    }
}

解決辦法

在屬性動(dòng)畫中有一類無限循環(huán)動(dòng)畫,如果在Activity中播放這類動(dòng)畫并且在onDestroy中去停止動(dòng)畫,那么這個(gè)動(dòng)畫將會(huì)一直播放下去,這時(shí)候Activity會(huì)被View所持有,從而導(dǎo)致Activity無法被釋放。解決此類問題則是需要早Activity中onDestroy去去調(diào)用objectAnimator.cancel()來停止動(dòng)畫。

@Override
protected void onDestroy() {
    super.onDestroy();
    mAnimator.cancel();
}

17.系統(tǒng)bug之InputMethodManager導(dǎo)致內(nèi)存泄漏

每次從MainActivity退出程序時(shí)總會(huì)報(bào)InputMethodManager內(nèi)存泄漏,原因系統(tǒng)中的InputMethodManager持有當(dāng)前MainActivity的引用,導(dǎo)致了MainActivity不能被系統(tǒng)回收,從而導(dǎo)致了MainActivity的內(nèi)存泄漏。查了很多資料,發(fā)現(xiàn)這是 Android SDK中輸入法的一個(gè)Bug,在15<=API<=23中都存在,目前Google還沒有解決這個(gè)Bug。

其他介紹 01.關(guān)于博客匯總鏈接

1.技術(shù)博客匯總

2.開源項(xiàng)目匯總

3.生活博客匯總

4.喜馬拉雅音頻匯總

5.其他匯總

02.關(guān)于我的博客

github:https://github.com/yangchong211

知乎:https://www.zhihu.com/people/...

簡書:http://www.jianshu.com/u/b7b2...

csdn:http://my.csdn.net/m0_37700275

喜馬拉雅聽書:http://www.ximalaya.com/zhubo...

開源中國:https://my.oschina.net/zbj161...

泡在網(wǎng)上的日子:http://www.jcodecraeer.com/me...

郵箱:yangchong211@163.com

阿里云博客:https://yq.aliyun.com/users/a... 239.headeruserinfo.3.dT4bcV

segmentfault頭條:https://segmentfault.com/u/xi...

掘金:https://juejin.im/user/593943...

項(xiàng)目開源地址:https://github.com/yangchong2... 項(xiàng)目開源地址:https://github.com/yangchong2...

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/75008.html

相關(guān)文章

  • 內(nèi)存 問題- 收藏集 - 掘金

    摘要:然而,中依然有可能發(fā)生內(nèi)存泄漏。所以你的安卓快速定位解決內(nèi)存泄漏掘金昨天是個(gè)好日子,程序員的節(jié)日,在這里給所有的程序員送上一份遲到的祝福。應(yīng)用內(nèi)存泄漏的定位分析與解決策略掘金,大家好,我是。 Android 性能優(yōu)化之巧用軟引用與弱引用優(yōu)化內(nèi)存使用 - Android - 掘金前言: 從事Android開發(fā)的同學(xué)都知道移動(dòng)設(shè)備的內(nèi)存使用是非常敏感的話題,今天我們來看下如何使用軟引用與弱...

    TIGERB 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

fanux

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<