真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化-創(chuàng)新互聯(lián)

前言
這個系列的文章:

1、用通俗易懂的講解方式,講解一門技術(shù)的實用價值
2、詳細(xì)書寫源碼的追蹤,源碼截圖,繪制類的結(jié)構(gòu)圖,盡量詳細(xì)地解釋原理的探索過程
3、提供Github 的 可運行的Demo工程,但是我所提供代碼,更多是提供思路,拋磚引玉,請酌情cv
4、集合整理原理探索過程中的一些坑,或者demo的運行過程中的注意事項
5、用gif圖,最直觀地展示demo運行效果

在濱州等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供網(wǎng)站設(shè)計制作、成都網(wǎng)站建設(shè) 網(wǎng)站設(shè)計制作按需定制開發(fā),公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),品牌網(wǎng)站設(shè)計,網(wǎng)絡(luò)營銷推廣,成都外貿(mào)網(wǎng)站制作,濱州網(wǎng)站建設(shè)費用合理。

如果覺得細(xì)節(jié)太細(xì),直接跳過看結(jié)論即可。本人能力有限,如若發(fā)現(xiàn)描述不當(dāng)之處,歡迎留言批評指正。
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
學(xué)到老活到老,路漫漫其修遠(yuǎn)兮。與眾君共勉 !,和我一起當(dāng)個CV工程師吧,手動滑稽

正文大綱
  • jvm內(nèi)存管理常識
  • 檢測以及處理內(nèi)存抖動
  • 檢測以及處理內(nèi)存泄漏
正文
jvm內(nèi)存管理常識

LMK (LowMemoryKill)機(jī)制 android底層會在系統(tǒng)內(nèi)存告急的時候,按照一定規(guī)則殺死一些進(jìn)程來滿足其他進(jìn)程的內(nèi)存需要。其中 消耗內(nèi)存的高低就是其中一項指標(biāo),所以,優(yōu)化app的內(nèi)存占用,能夠有效降低app被系統(tǒng)殺死的概率。
GC STW機(jī)制 GC,垃圾回收進(jìn)程,在GC線程執(zhí)行任務(wù)的時候,會存在一個 STW (stop the world) 機(jī)制,他就會把其他所有線程都掛起。如果GC非常頻繁地調(diào)用,那就會導(dǎo)致主線程不流暢,給用戶的感覺就是 卡頓。
內(nèi)存抖動頻繁引起OOM 內(nèi)存抖動太頻繁,導(dǎo)致大量對象頻繁創(chuàng)建和銷毀,會產(chǎn)生大量不連續(xù)的內(nèi)存空間,如果此時有一個大對象需要申請內(nèi)存,就有可能申請失敗,導(dǎo)致 OOM內(nèi)存溢出
一句話解釋 內(nèi)存泄漏長 生命周期的對象持有 短生命周期對象的強(qiáng)引用,在 短生命周期對象需要回收的時候發(fā)現(xiàn) 不能被回收,視為泄漏
GC回收 可達(dá)性分析
GC線程判定 一個對象是不是可以回收,是根據(jù)可達(dá)性分析算法,計算 GcRoot,從 GcRoot向下搜索,把 GcRoot沒有直接關(guān)聯(lián)的對象全部作為垃圾來回收。
強(qiáng)軟弱虛四大引用 強(qiáng)和虛自不必說。強(qiáng) 最常見,沒有特殊處理的都是強(qiáng)引用(包括,匿名內(nèi)部類會持有外部類的強(qiáng)引用)。虛引用沒什么用,不予討論。軟引用,用來定義一些還有用,但是不是必須的對象,使用 SoftRefrence<T>修飾,在內(nèi)存緊張的時候,GC回收之后,使用 SoftRefrence<T>修飾,如果系統(tǒng)還有足夠的內(nèi)存可用,那么軟引用關(guān)聯(lián)的對象就不會被回收。如果不足,則回收軟引用關(guān)聯(lián)的對象。弱引用( WeakRefrence<T>),比軟引用更弱一些,只要GC觸發(fā),弱引用關(guān)聯(lián)的對象就會被回收。
注意: 使用軟和弱引用,要判定關(guān)聯(lián)對象是否為空。

檢測以及處理內(nèi)存抖動
我們使用s開發(fā),平時我們運行app,一般會點 RunApp,但是還有另一個選擇, 那就是 profileApp, 運行app起來之后,會在as下方看到profile 窗點擊之后,as下方會出現(xiàn)profile,圖中會顯示網(wǎng)絡(luò),內(nèi)存和cpu使用情況
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化

如果內(nèi)存的圖中抖動得非常明顯,比如像這樣的心電圖一樣:
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
那就說明非常明顯存在內(nèi)存抖動,急需處理: 點擊內(nèi)存圖形區(qū)域之后,就能看到詳細(xì)的內(nèi)存變化情況,以及內(nèi)存分配情況:
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
這里有個坑:

如果你從圖形中觀察到,內(nèi)存走勢平穩(wěn),并沒有出現(xiàn)上滿模擬抖動的圖中那么夸張,是不是就不存在內(nèi)存抖動呢?并不是。因為我們的gc,是在內(nèi)存不可用的情況下才會去回收內(nèi)存,如果app占用內(nèi)存一直比較少,沒有觸及gc的臨界值,那么就不會出現(xiàn) 斷崖式下跌. 那么這樣就觀察不出內(nèi)存抖動了,怎么辦呢?

解決方法 在8.0以下的安卓手機(jī)上,在下方的位置上會出現(xiàn)一個Record按鈕(如果是8.0以上,你可以直接用拖拽的方式來截取一段內(nèi)存record):
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
點擊它,一段時間之后,再點一下:你就能在下方發(fā)現(xiàn)一張表格:
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
這張表格代表的是,你Record這段時間之內(nèi)創(chuàng)建的對象,點擊一下第二列 Allocations,對創(chuàng)建的數(shù)量進(jìn)行排序,找出創(chuàng)建次數(shù)最多的對象:
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
然后,點擊排行第一的String之后,會在右方看到
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
然后點擊其中的一個,又會看到一個新的窗口:
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
此為止,就找到了 創(chuàng)建對象 的 元兇,以這個為線索,找到你們自己包名下的類和方法,確定是我們自己的代碼在不合理地創(chuàng)建對象.

再往后,就是根據(jù)各自的業(yè)務(wù)代碼去做優(yōu)化了,記住一個宗旨:不要讓代碼干多余的事。 如果是我們調(diào)用了系統(tǒng)的api導(dǎo)致了不合理地大量對象的創(chuàng)建,那么就要考慮這個系統(tǒng)API為什么會這樣創(chuàng)建對象,有沒有其他方法避免嗎,從業(yè)務(wù)代碼層來合理使用這個api,實在不行再考慮自定義api或者換個系統(tǒng)api。

在我們做了一次優(yōu)化之后,再profile運行一次app,再重復(fù)上面的過程。以此類推,直到內(nèi)存抖動達(dá)到理想狀態(tài)。

總結(jié)

優(yōu)化內(nèi)存抖動,核心就是防止頻繁創(chuàng)建對象。常見的反面教材就是:循環(huán)中創(chuàng)建對象,大量調(diào)用的api中創(chuàng)建對象。而優(yōu)化的主要手段,就是對象復(fù)用,常見的手段是:對象池,像是 Handler的Message 單鏈表池,Glide的bitmap池等。

檢測以及處理內(nèi)存泄漏

經(jīng)典案例: 處理 handler異步任務(wù)導(dǎo)致的內(nèi)存泄漏方法

  • 在Activity的onDestroy中移除所有的任務(wù)
    @Override
    protected void onDestroy() {
        super.onDestroy();
        handler.removeCallbacksAndMessages(null);//移除所有任務(wù)
    }
  • 使用靜態(tài)內(nèi)部類 + Activity弱引用的方式
    MyHandler handler = new MyHandler(this);
    private  static class MyHandler extends Handler {
         WeakReference activityWeakReference;
         MyHandler(Activity activity) {
               activityWeakReference = new WeakReference<>(activity);
         }
         @Override
         public void handleMessage(Message msg) {
               //在執(zhí)行任務(wù)的時候,判斷弱引用所關(guān)聯(lián)的對象是否為空,能在對象已經(jīng)被回收的情況下
               switch (msg.what) {
                   case 1:
                       if (activityWeakReference.get() !=null) {
                            //T0D0
                       }
               }
         }
    }
工具的使用

依然是 profileApp,先用 profile看出內(nèi)存的變化情況。

問:如何判斷內(nèi)存泄漏?

答:內(nèi)存泄漏是精細(xì)功夫,不能全盤觀察,只能憑借profile的內(nèi)存變化來推測。比如,打開app之后內(nèi)存一路飆升,直到超出app能夠使用的大內(nèi)存,app崩潰,,這是最明顯的。又比如,你反復(fù)打開關(guān)閉某一個界面,發(fā)現(xiàn)內(nèi)存的穩(wěn)定線( 內(nèi)存穩(wěn)定之后,內(nèi)存占用值)隨著每一次的打開關(guān)閉,都在提高,這說明,這一個界面上存在泄漏,有對象無法被回收。

上一章節(jié)使用 profile 最多是了解到 哪些對象的創(chuàng)建和回收引起了內(nèi)存抖動,但是,涉及到泄漏,只通過profile尚且 不能知道是 哪個類持有了希望被回收的對象的強(qiáng)引用. 這里就要借助另外一款工具,他的名字叫做 EclipseMat (自行百度)

先回到剛才的 profile
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
點一下,然后再點一下,界面會自動跳轉(zhuǎn):
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
點擊上面的保存按鈕,將文件存到本地;

然后:
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
但是這個文件是無法直接在mat打開的

找到SDK目錄下的要 hprof-conv.exe
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化

使用cmd命令,對文件進(jìn)行轉(zhuǎn)換,命令為:hprof-conv[源文件名][目標(biāo)文件名]如 hprof-conv1.hprof2.hprof回車

將得到的 2.hprof利用剛才下載的Mat工具打開:
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
這里有很多指標(biāo),但是檢查內(nèi)存泄漏,我們只需要關(guān)注這個直方圖按鈕即可:手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化

這個圖中會列出你dump的這一段內(nèi)存中的所有對象,包括framework層的,也包括我們自己代碼創(chuàng)建的對象
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化

案例模擬

我模擬了一個經(jīng)典案例,也就是前面提到的 Handler延時任務(wù)導(dǎo)致 Activity不能被釋放,核心代碼如下

 public class SecondActivity extends AppComatActivity {
     Handler handler = new Handler();
     //創(chuàng)建一個強(qiáng)引用Activity的handler對象
     @Override
     protected void onCreate (Bundle savedInstancestate) {
           super.onCreate(saveInstanceState);
           setContentView(R.layout.activity_second);
           handler.postDelayed(new Runnable() {
                   @Override
                   public void run() {

                   }
           }, Integer.MAX_VALUE);
              //我讓任務(wù)永遠(yuǎn)在這里
    }

我就用一個非常普通的方式創(chuàng)建了一個 handler對象,并且用它來執(zhí)行一段延時任務(wù),只不過,延時任務(wù)的延時時間是 Integer的大值,也就是說,任務(wù)要很久以后才會執(zhí)行。之后,我反復(fù)進(jìn)出這一個 Activity,然后按照上面的方式 dump了一段 hprof,經(jīng)過 hprof-conv 轉(zhuǎn)化,然后用 Mat打開:結(jié)果如下
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
我填寫過濾信息: SecondActivity 回車
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
在我們最終退出SecondActivity之后,內(nèi)存中依然保留了 18個無用的對象。

那么是不是我們這18個都是泄漏的呢?
不一定
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
前文講過,只有不合理的強(qiáng)引用,才會導(dǎo)致內(nèi)存泄漏,所以我們要按照上面的方式排除軟弱虛引用。之后我們能看到下面的界面,把能展開的信息盡數(shù)展開
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
了解 Handler源碼的同志們應(yīng)該一眼就看明白了, handler引起了內(nèi)存泄漏,是因為存在不合理地強(qiáng)引用鏈, 上圖中可以看出,最終是callback對象持有了 SecondActivity對象。

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

我們剛才已經(jīng)看到了Handler的不合理使用導(dǎo)致了內(nèi)存泄漏,那么如果在 onDestroy中移除所有的任務(wù)

   @Override
    protected void onDestroy() {
          super.onDestroy();
          handler.removeCallbacksAndMessages(token.null):
    }
 }

執(zhí)行同樣的任務(wù),dump下來的hprof 在mat觸發(fā)了GC之后, SecondActivity數(shù)量變?yōu)榱?,內(nèi)存泄漏解決。

當(dāng)然還有另一種做法,靜態(tài)內(nèi)部類+弱引用。

ps: 靜態(tài)內(nèi)部類是為了防止內(nèi)部類持有外部類的引用,弱引用是為了在GC觸發(fā)之時,回收掉WeakRefrence中的對象。

public class secondActivity extends AppCompatActivity {
Handler handler = new Handler():
@Override
protected void onCreate(Bundle saveInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
handler.postDelayed(runnable, Integer.MAX_VALUE);
//依舊是那個延時很久的任務(wù)
}
Runnable runnable = new MyRunnable(this);
private static class MyRunnable implements Runnable {
//靜態(tài)內(nèi)部類
WeakReference<activity> activityWeakReference
//弱引用
MyRunnable(Activity activity) {
activityWeakReference = new WeakReference<>(activity);
}
@Override
public void run() {
}
}

手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
但是排除之后,一個都沒有了。

小技巧

上面的步驟雖然可行,但是如果有很多頁面都需要排查泄漏,那么我們一個一個頁面去點開關(guān)閉,整個過程將會非常冗長難受。其實有辦法解決?;氐街暗闹狈綀D:
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
使用方法為:如果你想進(jìn)行一個操作,你操作前后各dump一個hprof,命名為 before和after, 然后用hprof-conv轉(zhuǎn)換一下,變?yōu)?before 和 `after ,用eclipse mat同時打開這兩個文件,然后切換到after.hprof` ,點擊上圖中的按鈕

它會讓你選擇想要對比的文件,點擊before,然后過濾SecondActivity
手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化
這種方式可以在處理泄漏之前,事先排查可能泄露的代碼區(qū)域。簡化我們的優(yōu)化工作。

結(jié)語

內(nèi)存抖動和泄漏優(yōu)化涉及到Jvm很多知識點,除了我之前列出的幾點之外,還有很多細(xì)枝末節(jié)。要做好 內(nèi)存優(yōu)化,需要扎實的JVM知識基礎(chǔ)。

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)cdcxhl.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。


本文標(biāo)題:手把手帶你了解內(nèi)存抖動和泄漏的優(yōu)化-創(chuàng)新互聯(lián)
當(dāng)前地址:http://weahome.cn/article/jcjgp.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部