常見的八種導致 APP 記憶體流失的問題(上)

來源:互聯網
上載者:User

標籤:全域   測試   context   應該   分享   釋放   text   種類   單例   

百度搜尋:小強測試品牌

QQ群:138269539

像 Java 這樣具有記憶體回收功能的語言的好處之一,就是程式員無需手動管理記憶體配置。這減少了段錯誤(segmentation fault)導致的閃退,也減少了記憶體流失導致的堆空間膨脹,讓編寫的代碼更加安全。然而,Java 中依然有可能發生記憶體流失。所以你的安卓 APP 依然有可能浪費了大量的記憶體,甚至由於記憶體耗盡(OOM)導致閃退。

傳統的記憶體流失是由忘記釋放分配的記憶體導致的,而邏輯上的記憶體流失則是由於忘記在對象不再被使用的時候釋放對其的引用導致的。如果一個對象仍然存在強引用,記憶體回收行程就無法對其進行記憶體回收。在安卓平台,泄漏 Context 對象問題尤其嚴重。這是因為像Activity 這樣的 Context 對象會引用大量很佔用記憶體的對象,例如 View 層級,以及其他的資源。如果 Context 對象發生了記憶體流失,那它引用的所有對象都被泄漏了。安卓裝置大多記憶體有限,如果發生了大量這樣的記憶體流失,那記憶體將很快耗盡。

如果一個對象的合理生命週期沒有清晰的定義,那判斷邏輯上的記憶體流失將是一個見仁見智的問題。幸運的是,activity 有清晰的生命週期定義,使得我們可以很明確地判斷 activity 對象是否被記憶體流失。onDestroy() 函 數將在 activity 被銷毀時調用,無論是程式員主動銷毀 activity,還是系統為了回收記憶體而將其銷毀。如果 onDestroy 執行完畢之後,activity 對象仍被 heap root 強引用,那記憶體回收行程就無法將其回收。所以我們可以把生命週期結束之後仍被引用的 activity 定義為被泄漏的 activity。

Activity 是非常重量級的對象,所以我們應該極力避免妨礙系統對其進行回收。然而有多種方式會讓我們無意間就泄露了 activity 對象。

我們把可能導致 activity 泄漏的情況分為兩類,一類是使用了進程全域(process-global)的靜態變數,無論 APP 處於什麼狀態,都會一直存在,它們持有了對 activity 的強引用進而導致記憶體流失,另一類是生命週期長於 activity 的線程,它們忘記釋放對 activity 的強引用進而導致記憶體流失。下面我們就來詳細分析一下這些可能導致 activity 泄漏的情況。

靜態 Activity

泄漏 activity 最簡單的方法就是在 activity 類中定義一個 static 變數,並且將其指向一個運行中的 activity 執行個體。 如果在 activity 的生命

周期結束之前,沒有清除這個引用,那它就會泄漏了。這是因為 activity(例如 MainActivity) 的類對象是靜態,一旦載入,就會在

APP 運行時一直常駐記憶體,因此如果類對象不卸載,其靜態成員就不會被記憶體回收。

靜態 View

另一種類似的情況是對經常啟動的 activity 實現一個單例模式,讓其常駐記憶體可以使它能夠快速恢複狀態。然而,就像前文所述,不遵循系統定義的 activity 生命週期是非常危險的,也是沒必要的,所以我們應該極力避免。

但是如果我們有一個建立起來非常耗時的 View,在同一個 activity 不同的生命週期中都保持不變呢?所以讓我們為它實現一個單例模式,就像這段代碼。現在一旦 activity 被銷毀,那我們就應該釋放大部分的記憶體了

內 存泄漏了!因為一旦 view 被加入到介面中,它就會持有 context 的強引用,也就是我們的 activity。由於我們通過一個靜態成員引用了這個 view,所以我們也就引用了 activity,因此 activity 就發生了泄漏。所以一定不要把載入的 view 賦值給靜態變數,如果你真的需要,那一定要確保在 activity 銷毀之前將其從 view 層級中移除。

內部類

現在讓我們在 activity 內部定義一個類,也就是內部類。這樣做的原因有很多,比如增加封裝性和可讀性。如果我們建立了一個內部類的對象,並且通過靜態變數持有了 activity 的引用,那也會發生 activity 泄漏。

不幸的是,內部類能夠引用外部類的成員這一優勢,就是通過持有外部類的引用來實現的,而這正是 activity 泄漏的原因。

匿名類

類似的,匿名類同樣會持有定義它們的對象的引用。因此如果在 activity 內定義了一個匿名的 AsyncTask 對象,就有可能發生記憶體流失了。如果 activity 被銷毀之後 AsyncTask 仍然在執行,那就會組織記憶體回收行程回收 activity 對象,進而導致記憶體流失,直到執行結束才能回收 activity。

常見的八種導致 APP 記憶體流失的問題(上)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.