Android效能最佳化之記憶體洩露

renke發表於2021-09-09

前言

效能最佳化目的:
1.如何去最佳化自己的專案,執行更流暢。

現實App程式分配記憶體空間: 16M 32M 64M

2..以後開發專案的時候就要從一開始把專案做好

記憶體洩露

不是所有指令都執行得又快又好,下面介紹記憶體及它如何影響系統執行。普遍認為,多數程式語言接近硬體或高效能,如C、C++和Fortran,通常程式設計師會自己管理記憶體,高手工程師對記憶體的分配,會慎重處理,並在未來結束使用時再次分配,一旦確認何時及怎樣分配記憶體,記憶體管理的品質就依賴於工程師的技能跟效率。實際情況是工程師們,不都會去追蹤那零碎的記憶體碎片。程式開發是個混亂又瘋狂的過程,記憶體通常都沒辦法完全被釋放,這些被囚禁的記憶體叫記憶體洩露。

圖片描述

記憶體洩露佔用了大量資源,這些資源其實可以更好地使用,為減少洩露引起的混亂、負擔、甚至資金損失,便有了記憶體管理語言。

圖片描述

這些語言在執行時跟蹤記憶體分配,以便當程式不再需要時釋放系統記憶體,完全不用工程師親自操作,這些記憶體回收藝術或科學,在記憶體管理環節下叫垃圾清理。這個設計概念在1959年,當初為了解決lisp語言問題,由John McCarthy發明的。

垃圾清理的基本概念有:

第一,找到未來無法存取的資料,例如所有不受指令操控的記憶體。
第二,回收被利用過的資源。原理簡單,但是兩百萬行編碼,跟4gigs的分配,在實際操作時卻非常困難。如果在程式中有20000個物件分配,垃圾清理會讓人困惑,哪一個是沒用的?或者,何時啟動垃圾清理釋放記憶體?這些問題其實很複雜。好在50年來,我們找到了解決問題的方法,就是Android Runtime中的垃圾清理。比McCarthy最初的方法更高階,速度快且是非侵入性的。經由分配型別,及系統如何有效地組織分配以利GC的執行,並作為新的配置。所有影響android runtime的記憶體堆都被分割到空間中,根據這些特點,哪些資料適合放到什麼空間,取決於哪個Android版本。

圖片描述

瞭解記憶體分配的幾種策略:

1.靜態的
在編譯時就能確定每個資料目標在執行時刻的儲存空間需求,因而在編譯時就可以給他們分配固定的記憶體空間.這種分配策略要求程式程式碼中不允許有可變程式碼結構(比如可變陣列的存在),也不允許有巢狀或者遞迴結構的出現,因為它們都會導致編譯程式無法計算準確的儲存空間需求。

2.棧式的
棧式儲存分配也可稱為動態儲存分配,是由一個類似於堆疊的執行棧來實現的.和靜態儲存分配相反,在棧式儲存方案中,程式對資料區的需求在編譯時是完全未知的,只有到執行的時候才能夠知道,但是規定在執行中進入一個程式模組時,必須知道該程式模組所需的資料區大小才能夠為其分配記憶體.和我們在資料結構所熟知的棧一樣,棧式儲存分配按照先進後出的原則進行分配。

3.堆式的
堆式儲存分配則專門負責在編譯時或執行時模組入口處都無法確定儲存要求的資料結構的記憶體分配,比如可變長度串和物件例項.堆由大片的可利用塊或空閒塊組成,堆中的記憶體可以按照任意順序分配和釋放.
在C/C++可能需要自己負責釋放(java裡面直接額依賴GC機制)

棧式和堆式區別:
public class Main{    int a = 1;//堆裡面
    Student s = new Student();//堆裡面
    public void XXX(){//堆裡面
        int b = 1;//棧裡面
        Student s2 = new Student();
    }

}

1.成員變數全部儲存在堆中(包括基本資料型別,引用和引用的物件實體) --- 因為它們屬於類,類最終還是要被new出來。
2.區域性變數的基本資料型別和引用儲存於棧當中,引用的物件實體儲存於在堆中。-----因為他們屬於方法當中的變數,生命週期會隨著方法一起結束。

圖片描述

我們所討論的記憶體洩漏,主要是討論堆儲存,它存放的是引用指向的物件實體。

有時候確實會有一種情況:當需要的時候可以訪問,當不需要的時候可以被回收也可以被暫時儲存以備重複使用。
比如:ListView或者GridView、REcyclerView載入大量資料或者圖片的時候,
圖片非常佔用記憶體,一定要管理好記憶體,不然很容易記憶體溢位。
滑出去的圖片就回收,節省記憶體。看ListView的原始碼----回收物件,還會重用ConvertView。
如果使用者反覆滑動或者下面還有同樣的圖片,就會造成多次重複IO(很耗時),
那麼需要快取---平衡好記憶體大小和IO,演算法和一些特殊的java類。
演算法:lrucache(最近最少使用先回收)
特殊的java類:利於回收,StrongReference,SoftReference,WeakReference,PhatomReference

StrongReference --- 強引用:
StrongReference 是 Java的預設引用實現, 它會盡可能長時間的存活於 JVM 內, 當沒有任何物件指向它時 GC 執行後將會被回收

回收時機:從不回收 使用:物件的一般儲存 生命週期:JVM停止的時候才會終止

SoftReference --- 軟引用

SoftReference 於 WeakReference 的特性基本一致, 最大的區別在於 SoftReference 會盡可能長的保留引用直到 JVM 記憶體不足時才會被回收(虛擬機器保證), 這一特性使得 SoftReference 非常適合快取應用
回收時機:當記憶體不足的時候;使用:SoftReference結合ReferenceQueue構造有效期短;生命週期:記憶體不足時終止

WeakReference --- 弱引用

WeakReference 是一個弱引用, 當所引用的物件在 JVM 內不再有強引用時, GC 後 weak reference 將會被自動回
回收時機:在垃圾回收的時候;使用:同軟引用; 生命週期:GC後終止

PhatomReference --- 虛引用

“虛引用”顧名思義,就是形同虛設,與其他幾種引用都不同,虛引用並不會決定物件的生命週期。如果一個物件僅>持有虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。
虛引用主要用來跟蹤物件被垃圾回收器回收的活動。虛引用與軟引用和弱引用的一個區別在於:虛引用必須和引用>佇列 (ReferenceQueue)聯合使用。當垃圾回收器準備回收一個物件時,如果發現它還有虛引用,就會在回收對
象的記憶體之前,把這個虛引用加入到與之 關聯的引用佇列中。
ReferenceQueue queue = new ReferenceQueue ();
PhantomReference pr = new PhantomReference (object, queue);
程式可以透過判斷引用佇列中是否已經加入了虛引用,來了解被引用的物件是否將要被垃圾回收。如果程式發現某個虛引用已經被加入到引用佇列,那麼就可以在所引用的物件的記憶體被回收之前採取必要的行動。
回收時機:在垃圾回收的時候;使用:合ReferenceQueue來跟蹤物件被垃圾回收期回收的活動; 生命週期:GC後終止

開發時,為了防止記憶體溢位,處理一些比較佔用記憶體大並且生命週期長的物件的時候,可以儘量使用軟引用和弱引用。軟引用比LRU演算法更加任性,回收量是比較大的,你無法控制回收哪些物件。

比如使用場景:預設頭像、預設圖示。
ListView或者GridView、RecyclerView要使用內部快取+外部快取(SD卡)

-----------------------------記憶體洩漏例子--------------------------
單例模式導致記憶體物件無法釋放而導致記憶體洩漏

public class CommonUtils {    private static CommonUtils instance;    private Context context;    private CommonUtils(Context context) {        this.context = context;
    }    public static CommonUtils getInstance(Context context) {        if (instance == null) {
            instance = new CommonUtils(context);
        }        return instance;
    }
}
public class MainActivity extends AppCompatActivity {    @Override
    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

       CommonUtils commonUtils =  CommonUtils.getInstance(this);


    }
}
執行這個簡單的單例模式程式,進行多次橫豎屏切換,發現可用記憶體越來越小,存在記憶體洩漏現象,最終導致記憶體溢位。

圖片描述

分析原因:

圖片描述

總結
我們能用Application的context就用Application的
CommonUtils 生命週期是跟Application程式同生同死。

原文連結:http://www.apkbus.com/blog-822415-77058.html

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/430/viewspace-2812520/,如需轉載,請註明出處,否則將追究法律責任。

相關文章