1. 程式人生 > >非靜態內部類/匿名類引起的Memory Leak

非靜態內部類/匿名類引起的Memory Leak

在最近使用okhttp3的過程中,使用LeakCanary檢查發現引起了memory leak,排查後發現洩露發生在okhttp3.Callback中,順便學習了非靜態內部類/匿名類引起的記憶體洩漏問題,現摘錄如下。

在JAVA中,非靜態內部類/匿名類會隱式的持有外部類的引用,如果是外部類是Activity,在退出Activity後,系統不能回收Activity的資源,
導致記憶體洩漏。
解決這一問題,只需要將非靜態內部類/匿名類改為靜態的,靜態的內部類/匿名類不會持有外部類的應用,這樣系統就可以正常回收外部類的資源了。

“`
private static class UserBehaviorCallback implements okhttp3.Callback{

    @Override
    public void onFailure(Call call, IOException e) {
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
    }
}

OkHttpClient client = OkHttpUtils.getInstance().getOkHttpClient();

    //192.168.192.102 --> 192.168.13.7
    String json = new Gson().toJson(params);
    RequestBody body = RequestBody.create(JSON, json);
    okhttp3.Request request = new okhttp3.Request.Builder()
            .url("")
            .post(body)
            .build();
    client.newCall(request).enqueue(new UserBehaviorCallback());

在Android中,長時間執行的任務和Acyivity生命週期進行協調會有點困難,如果你不加以小心的話會導致記憶體洩漏。關於如何處理這個棘手的問題,下面有幾個基本的技巧供參考

1、使用靜態內部類/匿名類,不要使用非靜態內部類/匿名類.非靜態內部類/匿名類會隱式的持有外部類的引用,外部類就有可能發生洩漏。而靜態內部類/匿名類不會隱式的持有外部類引用,外部類會以正常的方式回收,如果你想在靜態內部類/匿名類中使用外部類的屬性或方法時,可以顯示的持有一個弱引用。

2、不要以為Java永遠會幫你清理回收正在執行的threads.在上面的程式碼中,我們很容易誤以為當Activity結束銷燬時會幫我們把正在執行的thread也結束回收掉,但事情永遠不是這樣的!Java threads會一直存在,只有當執行緒執行完成或被殺死掉,執行緒才會被回收。所以我們應該養成為thread設定退出邏輯條件的習慣。

3、適當的考慮下是否應該使用執行緒.Android應用框架設計了許多的類來簡化執行後臺任務,我們可以使用與Activity生命週期相關聯的Loaders來執行簡短的後臺查詢任務。如果一個執行緒不依賴與Activity,我們還可以使用Service來執行後臺任務,然後用BroadcastReceiver來向Activity報告結果。另外需要注意的是本文討論的thread同樣使用於AsyncTasks,AsyncTask同樣也是由執行緒來實現,只不過使用了Java5.0新增併發包中的功能,但同時需要注意的是根據官方文件所說,AsyncTask適用於執行一些簡短的後臺任務