新手常見內存問題

內存溢出

抓狂的oom,這個錯誤拋出的原理

內存泄漏

當內存不足時,Android運行時就會觸發GC,GC採用的垃圾標記算法爲根搜索算法。內存泄漏就是指沒有用的對象到GC root是可達的,導致GC無法回收該對象。

內存泄漏的場景

  1. 非靜態內部類的靜態實例,如
public class InnerActivity extends AppCompatActivity {
    private static Object inner;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_inner);
        //
        inner=new InnerClass();
    }

    class InnerClass{}
}

靜態實例inner生命週期與應用程序一樣長,它持有InnerActivity的引用,導致InnerActivity無法被回收。

  1. 多線程相關的非靜態內部類
public class InnerActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_inner);

        startAsyncTask();
    }
    void startAsyncTask(){
        new AsyncTask<Void,Void,Void>(){
            @Override
            protected Void doInBackground(Void... voids) {
                while (true){//耗時任務
                }
            }
        }.execute();
    }
}

AsyncTask的內部匿名類,如果線程不結束,則一直持有Activity的引用。我們可以會使用靜態AsyncTask或者退出Activity時結束異步線程。

  1. Handler內存泄露
    HandlerMessage被存儲在MessageQueue中, 有些Message不能立即處理,它們會在MessageQueue存在很長時間,這會導致Handler無法被回收。如果Handler是非靜態的,則引用它的ActivityService不能被回收。

解決方案:

  • 一個是使用靜態的Handler內部類,持有的引用使用弱引用
  • activityDestory方法中,調用handler.removeCallbacksAndMessages(null);來移除MessageQueue中的Message.
  1. 未正確使用Context
    對於不是必須使用Activity的Context情況,可以考慮使用Application Context來代替,特別是單例的情況。

  2. WebView
    在應用中只要使用一次WebView,內存就不會被釋放掉。通常的解決辦法是爲WebView單開一個進程,使用AIDL與應用進行通信。WebView可以根據業務需求在合適的時機進行銷燬。

6.資源對象未關閉
資源對象比如Curso、File等,往往都使用了

內存分析

通過內存分析來發現泄漏點

避免內存抖動

頻煩的內存申請及釋放,會導致短時間的頻煩GC,會嚴重影響程序性能。
解決方法:不要申請大量不必要的對象內存:
1, 不可變對象:String
2, 自動裝箱:Integer, Boolean...
考慮使用對象池並緩存來減少內存抖動
留心enum類型的開銷(一個指向枚舉類型的引用就要佔據4個字節)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章