国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

Android GC原理探究

移動(dòng)開發(fā) Android
想寫一篇關(guān)于android GC的想法來(lái)源于追查一個(gè)魅族手機(jī)圖片滑動(dòng)卡頓問(wèn)題,由于不斷的GC導(dǎo)致的丟幀卡頓的問(wèn)題讓我們想了很多方案去解決,所以就打算詳細(xì)的看看內(nèi)存分配和GC的原理,為什么會(huì)不斷的GC,GC ALLOC和GC COCURRENT有什么區(qū)別,能不能想辦法擴(kuò)大堆內(nèi)存減少GC的頻次等等。

[[191646]]

前言

想寫一篇關(guān)于android GC的想法來(lái)源于追查一個(gè)魅族手機(jī)圖片滑動(dòng)卡頓問(wèn)題,由于不斷的GC導(dǎo)致的丟幀卡頓的問(wèn)題讓我們想了很多方案去解決,所以就打算詳細(xì)的看看內(nèi)存分配和GC的原理,為什么會(huì)不斷的GC,GC ALLOC和GC COCURRENT有什么區(qū)別,能不能想辦法擴(kuò)大堆內(nèi)存減少GC的頻次等等。

1、JVM內(nèi)存回收機(jī)制

1.1 回收算法

標(biāo)記回收算法(Mark and Sweep GC)

從”GC Roots”集合開始,將內(nèi)存整個(gè)遍歷一次,保留所有可以被GC Roots直接或間接引用到的對(duì)象,而剩下的對(duì)象都當(dāng)作垃圾對(duì)待并回收,這個(gè)算法需要中斷進(jìn)程內(nèi)其它組件的執(zhí)行并且可能產(chǎn)生內(nèi)存碎片

復(fù)制算法 (Copying)

將現(xiàn)有的內(nèi)存空間分為兩快,每次只使用其中一塊,在垃圾回收時(shí)將正在使用的內(nèi)存中的存活對(duì)象復(fù)制到未被使用的內(nèi)存塊中,之后,清除正在使用的內(nèi)存塊中的所有對(duì)象,交換兩個(gè)內(nèi)存的角色,完成垃圾回收。

標(biāo)記-壓縮算法 (Mark-Compact)

先需要從根節(jié)點(diǎn)開始對(duì)所有可達(dá)對(duì)象做一次標(biāo)記,但之后,它并不簡(jiǎn)單地清理未標(biāo)記的對(duì)象,而是將所有的存活對(duì)象壓縮到內(nèi)存的一端。之后,清理邊界外所有的空間。這種方法既避免了碎片的產(chǎn)生,又不需要兩塊相同的內(nèi)存空間,因此,其性價(jià)比比較高。

分代

將所有的新建對(duì)象都放入稱為年輕代的內(nèi)存區(qū)域,年輕代的特點(diǎn)是對(duì)象會(huì)很快回收,因此,在年輕代就選擇效率較高的復(fù)制算法。當(dāng)一個(gè)對(duì)象經(jīng)過(guò)幾次回收后依然存活,對(duì)象就會(huì)被放入稱為老生代的內(nèi)存空間。對(duì)于新生代適用于復(fù)制算法,而對(duì)于老年代則采取標(biāo)記-壓縮算法。

1.2 復(fù)制和標(biāo)記-壓縮算法的區(qū)別

乍一看這兩個(gè)算法似乎并沒(méi)有多大的區(qū)別,都是標(biāo)記了然后挪到另外的內(nèi)存地址進(jìn)行回收,那為什么不同的分代要使用不同的回收算法呢?

其實(shí)2者***的區(qū)別在于前者是用空間換時(shí)間后者則是用時(shí)間換空間。

前者的在工作的時(shí)候是不沒(méi)有獨(dú)立的“mark”與“copy”階段的,而是合在一起做一個(gè)動(dòng)作,就叫scavenge(或evacuate,或者就叫copy)。也就是說(shuō),每發(fā)現(xiàn)一個(gè)這次收集中尚未訪問(wèn)過(guò)的活對(duì)象就直接copy到新地方,同時(shí)設(shè)置forwarding pointer。這樣的工作方式就需要多一份空間。

后者在工作的時(shí)候則需要分別的mark與compact階段,mark階段用來(lái)發(fā)現(xiàn)并標(biāo)記所有活的對(duì)象,然后compact階段才移動(dòng)對(duì)象來(lái)達(dá)到compact的目的。如果compact方式是sliding compaction,則在mark之后就可以按順序一個(gè)個(gè)對(duì)象“滑動(dòng)”到空間的某一側(cè)。因?yàn)橐呀?jīng)先遍歷了整個(gè)空間里的對(duì)象圖,知道所有的活對(duì)象了,所以移動(dòng)的時(shí)候就可以在同一個(gè)空間內(nèi)而不需要多一份空間。

所以新生代的回收會(huì)更快一點(diǎn),老年代的回收則會(huì)需要更長(zhǎng)時(shí)間,同時(shí)壓縮階段是會(huì)暫停應(yīng)用的,所以給我們應(yīng)該盡量避免對(duì)象出現(xiàn)在老年代。

2、Dalvik虛擬機(jī)

2.1 java堆

Java堆實(shí)際上是由一個(gè)Active堆和一個(gè)Zygote堆組成的,其中,Zygote堆用來(lái)管理Zygote進(jìn)程在啟動(dòng)過(guò)程中預(yù)加載和創(chuàng)建的各種對(duì)象,而Active堆是在Zygote進(jìn)程fork***個(gè)子進(jìn)程之前創(chuàng)建的。以后啟動(dòng)的所有應(yīng)用程序進(jìn)程是被Zygote進(jìn)程fork出來(lái)的,并都持有一個(gè)自己的Dalvik虛擬機(jī)。在創(chuàng)建應(yīng)用程序的過(guò)程中,Dalvik虛擬機(jī)采用COW策略復(fù)制Zygote進(jìn)程的地址空間。

COW策略:一開始的時(shí)候(未復(fù)制Zygote進(jìn)程的地址空間的時(shí)候),應(yīng)用程序進(jìn)程和Zygote進(jìn)程共享了同一個(gè)用來(lái)分配對(duì)象的堆。當(dāng)Zygote進(jìn)程或者應(yīng)用程序進(jìn)程對(duì)該堆進(jìn)行寫操作時(shí),內(nèi)核就會(huì)執(zhí)行真正的拷貝操作,使得Zygote進(jìn)程和應(yīng)用程序進(jìn)程分別擁有自己的一份拷貝,這就是所謂的COW。因?yàn)閏opy是十分耗時(shí)的,所以必須盡量避免copy或者盡量少的copy。

為了實(shí)現(xiàn)這個(gè)目的,當(dāng)創(chuàng)建***個(gè)應(yīng)用程序進(jìn)程時(shí),會(huì)將已經(jīng)使用了的那部分堆內(nèi)存劃分為一部分,還沒(méi)有使用的堆內(nèi)存劃分為另外一部分。前者就稱為Zygote堆,后者就稱為Active堆。這樣只需把zygote堆中的內(nèi)容復(fù)制給應(yīng)用程序進(jìn)程就可以了。以后無(wú)論是Zygote進(jìn)程,還是應(yīng)用程序進(jìn)程,當(dāng)它們需要分配對(duì)象的時(shí)候,都在Active堆上進(jìn)行。這樣就可以使得Zygote堆盡可能少地被執(zhí)行寫操作,因而就可以減少執(zhí)行寫時(shí)拷貝的操作。在Zygote堆里面分配的對(duì)象其實(shí)主要就是Zygote進(jìn)程在啟動(dòng)過(guò)程中預(yù)加載的類、資源和對(duì)象了。這意味著這些預(yù)加載的類、資源和對(duì)象可以在Zygote進(jìn)程和應(yīng)用程序進(jìn)程中做到長(zhǎng)期共享。這樣既能減少拷貝操作,還能減少對(duì)內(nèi)存的需求。

2.2 和GC有關(guān)的一些指標(biāo)

記得我們之前在優(yōu)化魅族某手機(jī)的gc卡頓問(wèn)題時(shí),發(fā)現(xiàn)他很容易觸發(fā)GC_FOR_MALLOC,這個(gè)GC類別后續(xù)會(huì)說(shuō)到,是分配對(duì)象內(nèi)存不足時(shí)導(dǎo)致的。可是我們又設(shè)置了很大的堆Size為什么還會(huì)內(nèi)存不夠呢,這里需要了解以下幾個(gè)概念:分別是Java堆的起始大小(Starting Size)、***值(Maximum Size)和增長(zhǎng)上限值(Growth Limit)。

在啟動(dòng)Dalvik虛擬機(jī)的時(shí)候,我們可以分別通過(guò)-Xms、-Xmx和-XX:HeapGrowthLimit三個(gè)選項(xiàng)來(lái)指定上述三個(gè)值,以上三個(gè)值分別表示表示

  • Starting Size: Dalvik虛擬機(jī)啟動(dòng)的時(shí)候,會(huì)先分配一塊初始的堆內(nèi)存給虛擬機(jī)使用。
  • Growth Limit:是系統(tǒng)給每一個(gè)程序的***堆上限,超過(guò)這個(gè)上限,程序就會(huì)OOM
  • Maximum Size:不受控情況下的***堆內(nèi)存大小,起始就是我們?cè)谟胠argeheap屬性的時(shí)候,可以從系統(tǒng)獲取的***堆大小

同時(shí)除了上面的這個(gè)三個(gè)指標(biāo)外,還有幾個(gè)指標(biāo)也是值得我們關(guān)注的,那就是堆最小空閑值(Min Free)、堆***空閑值(Max Free)和堆目標(biāo)利用率(Target Utilization)。假設(shè)在某一次GC之后,存活對(duì)象占用內(nèi)存的大小為L(zhǎng)iveSize,那么這時(shí)候堆的理想大小應(yīng)該為(LiveSize / U)。但是(LiveSize / U)必須大于等于(LiveSize + MinFree)并且小于等于(LiveSize + MaxFree),每次GC后垃圾回收器都會(huì)盡量讓堆的利用率往目標(biāo)利用率靠攏。所以當(dāng)我們嘗試手動(dòng)去生成一些幾百K的對(duì)象,試圖去擴(kuò)大可用堆大小的時(shí)候,反而會(huì)導(dǎo)致頻繁的GC,因?yàn)檫@些對(duì)象的分配會(huì)導(dǎo)致GC,而GC后會(huì)讓堆內(nèi)存回到合適的比例,而我們使用的局部變量很快會(huì)被回收理論上存活對(duì)象還是那么多,我們的堆大小也會(huì)縮減回來(lái)無(wú)法達(dá)到擴(kuò)充的目的。 與此同時(shí)這也是產(chǎn)生CONCURRENT GC的一個(gè)因素,后文我們會(huì)詳細(xì)講到。

2.3 GC的類型

  • GC_FOR_MALLOC: 表示是在堆上分配對(duì)象時(shí)內(nèi)存不足觸發(fā)的GC。
  • GC_CONCURRENT: 當(dāng)我們應(yīng)用程序的堆內(nèi)存達(dá)到一定量,或者可以理解為快要滿的時(shí)候,系統(tǒng)會(huì)自動(dòng)觸發(fā)GC操作來(lái)釋放內(nèi)存。
  • GC_EXPLICIT: 表示是應(yīng)用程序調(diào)用System.gc、VMRuntime.gc接口或者收到SIGUSR1信號(hào)時(shí)觸發(fā)的GC。
  • GC_BEFORE_OOM: 表示是在準(zhǔn)備拋OOM異常之前進(jìn)行的***努力而觸發(fā)的GC。

實(shí)際上,GC_FOR_MALLOC、GC_CONCURRENT和GC_BEFORE_OOM三種類型的GC都是在分配對(duì)象的過(guò)程觸發(fā)的。而并發(fā)和非并發(fā)GC的區(qū)別主要在于前者在GC過(guò)程中,有條件地掛起和喚醒非GC線程,而后者在執(zhí)行GC的過(guò)程中,一直都是掛起非GC線程的。并行GC通過(guò)有條件地掛起和喚醒非GC線程,就可以使得應(yīng)用程序獲得更好的響應(yīng)性。但是同時(shí)并行GC需要多執(zhí)行一次標(biāo)記根集對(duì)象以及遞歸標(biāo)記那些在GC過(guò)程被訪問(wèn)了的對(duì)象的操作,所以也需要花費(fèi)更多的CPU資源。后文在Art的并發(fā)和非并發(fā)GC中我們也會(huì)著重說(shuō)明下這兩者的區(qū)別。

2.4 對(duì)象的分配和GC觸發(fā)時(shí)機(jī)

  1. 調(diào)用函數(shù)dvmHeapSourceAlloc在Java堆上分配指定大小的內(nèi)存。如果分配成功,那么就將分配得到的地址直接返回給調(diào)用者了。函數(shù)dvmHeapSourceAlloc在不改變Java堆當(dāng)前大小的前提下進(jìn)行內(nèi)存分配,這是屬于輕量級(jí)的內(nèi)存分配動(dòng)作。
  2. 如果上一步內(nèi)存分配失敗,這時(shí)候就需要執(zhí)行一次GC了。不過(guò)如果GC線程已經(jīng)在運(yùn)行中,即gDvm.gcHeap->gcRunning的值等于true,那么就直接調(diào)用函數(shù)dvmWaitForConcurrentGcToComplete等到GC執(zhí)行完成就是了。否則的話,就需要調(diào)用函數(shù)gcForMalloc來(lái)執(zhí)行一次GC了,參數(shù)false表示不要回收軟引用對(duì)象引用的對(duì)象。
  3. GC執(zhí)行完畢后,再次調(diào)用函數(shù)dvmHeapSourceAlloc嘗試輕量級(jí)的內(nèi)存分配操作。如果分配成功,那么就將分配得到的地址直接返回給調(diào)用者了。
  4. 如果上一步內(nèi)存分配失敗,這時(shí)候就得考慮先將Java堆的當(dāng)前大小設(shè)置為Dalvik虛擬機(jī)啟動(dòng)時(shí)指定的Java堆***值,再進(jìn)行內(nèi)存分配了。這是通過(guò)調(diào)用函數(shù)dvmHeapSourceAllocAndGrow來(lái)實(shí)現(xiàn)的。
  5. 如果調(diào)用函數(shù)dvmHeapSourceAllocAndGrow分配內(nèi)存成功,則直接將分配得到的地址直接返回給調(diào)用者了。
  6. 如果上一步內(nèi)存分配還是失敗,這時(shí)候就得出狠招了。再次調(diào)用函數(shù)gcForMalloc來(lái)執(zhí)行GC。參數(shù)true表示要回收軟引用對(duì)象引用的對(duì)象。
  7. GC執(zhí)行完畢,再次調(diào)用函數(shù)dvmHeapSourceAllocAndGrow進(jìn)行內(nèi)存分配。這是***一次努力了,成功與事都到此為止。

示例圖如下:

 

通過(guò)這個(gè)流程可以看到,在對(duì)象的分配中會(huì)導(dǎo)致GC,***次分配對(duì)象失敗我們會(huì)觸發(fā)GC但是不回收Soft的引用,如果再次分配還是失敗我們就會(huì)將Soft的內(nèi)存也給回收,前者觸發(fā)的GC是GC_FOR_MALLOC類型的GC,后者是GC_BEFORE_OOM類型的GC。而當(dāng)內(nèi)存分配成功后,我們會(huì)判斷當(dāng)前的內(nèi)存占用是否是達(dá)到了GC_CONCURRENT的閥值,如果達(dá)到了那么又會(huì)觸發(fā)GC_CONCURRENT。

那么這個(gè)閥值又是如何來(lái)的呢,上面我們說(shuō)到的一個(gè)目標(biāo)利用率,GC后我們會(huì)記錄一個(gè)目標(biāo)值,這個(gè)值理論上需要再上述的范圍之內(nèi),如果不在我們會(huì)選取邊界值做為目標(biāo)值。虛擬機(jī)會(huì)記錄這個(gè)目標(biāo)值,當(dāng)做當(dāng)前允許總的可以分配到的內(nèi)存。同時(shí)根據(jù)目標(biāo)值減去固定值(200~500K),當(dāng)做觸發(fā)GC_CONCURRENT事件的閾值。

2.5 回收算法和內(nèi)存碎片

主流的大部分Davik采取的都是標(biāo)注與清理(Mark and Sweep)回收算法,也有實(shí)現(xiàn)了拷貝GC的,這一點(diǎn)和HotSpot是不一樣的,具體使用什么算法是在編譯期決定的,無(wú)法在運(yùn)行的時(shí)候動(dòng)態(tài)更換。如果在編譯dalvik虛擬機(jī)的命令中指明了”WITH_COPYING_GC”選項(xiàng),則編譯”/dalvik/vm/alloc/Copying.cpp”源碼 – 此是Android中拷貝GC算法的實(shí)現(xiàn),否則編譯”/dalvik/vm/alloc/HeapSource.cpp” – 其實(shí)現(xiàn)了標(biāo)注與清理GC算法。

由于Mark and Sweep算法的缺點(diǎn),容易導(dǎo)致內(nèi)存碎片,所以在這個(gè)算法下,當(dāng)我們有大量不連續(xù)小內(nèi)存的時(shí)候,再分配一個(gè)較大對(duì)象時(shí),還是會(huì)非常容易導(dǎo)致GC,比如我們?cè)谠撌謾C(jī)上decode圖片,具體情況如下:

 

所以對(duì)于Dalvik虛擬機(jī)的手機(jī)來(lái)說(shuō),我們首先要盡量避免掉頻繁生成很多臨時(shí)小變量(比如說(shuō):getView,onDraw等函數(shù)),另一個(gè)又要盡量去避免產(chǎn)生很多長(zhǎng)生命周期的大對(duì)象。

3、ART內(nèi)存回收機(jī)制

3.1 Java堆

ART運(yùn)行時(shí)內(nèi)部使用的Java堆的主要組成包括Image Space、Zygote Space、Allocation Space和Large Object Space四個(gè)Space,Image Space用來(lái)存在一些預(yù)加載的類, Zygote Space和Allocation Space與Dalvik虛擬機(jī)垃圾收集機(jī)制中的Zygote堆和Active堆的作用是一樣的,

Large Object Space就是一些離散地址的集合,用來(lái)分配一些大對(duì)象從而提高了GC的管理效率和整體性能,類似如下圖:

 

在下文的GC Log中,我們也能看到在art的GC Log中包含了LOS的信息,方便我們查看大內(nèi)存的情況。

3.2 GC的類型

  • kGcCauseForAlloc ,當(dāng)要分配內(nèi)存的時(shí)候發(fā)現(xiàn)內(nèi)存不夠的情況下引起的GC,這種情況下的GC會(huì)stop world
  • kGcCauseBackground,當(dāng)內(nèi)存達(dá)到一定的閥值的時(shí)候會(huì)去出發(fā)GC,這個(gè)時(shí)候是一個(gè)后臺(tái)gc,不會(huì)引起stop world
  • kGcCauseExplicit,顯示調(diào)用的時(shí)候進(jìn)行的gc,如果art打開了這個(gè)選項(xiàng)的情況下,在system.gc的時(shí)候會(huì)進(jìn)行g(shù)c
  • 其他更多

3.3 對(duì)象的分配和GC觸發(fā)時(shí)機(jī)

由于Art下內(nèi)存分配和Dalvik下基本沒(méi)有任何區(qū)別,我直接貼圖帶過(guò)了。

 

3.4 并發(fā)和非并發(fā)GC

Art在GC上不像Dalvik僅有一種回收算法,Art在不同的情況下會(huì)選擇不同的回收算法,比如Alloc內(nèi)存不夠的時(shí)候會(huì)采用非并發(fā)GC,而在Alloc后發(fā)現(xiàn)內(nèi)存達(dá)到一定閥值的時(shí)候又會(huì)觸發(fā)并發(fā)GC。同時(shí)在前后臺(tái)的情況下GC策略也不盡相同,后面我們會(huì)一一給大家說(shuō)明。

非并發(fā)GC

步驟1. 調(diào)用子類實(shí)現(xiàn)的成員函數(shù)InitializePhase執(zhí)行GC初始化階段。

步驟2. 掛起所有的ART運(yùn)行時(shí)線程。

步驟3. 調(diào)用子類實(shí)現(xiàn)的成員函數(shù)MarkingPhase執(zhí)行GC標(biāo)記階段。

步驟4. 調(diào)用子類實(shí)現(xiàn)的成員函數(shù)ReclaimPhase執(zhí)行GC回收階段。

步驟5. 恢復(fù)第2步掛起的ART運(yùn)行時(shí)線程。

步驟6. 調(diào)用子類實(shí)現(xiàn)的成員函數(shù)FinishPhase執(zhí)行GC結(jié)束階段。

并發(fā)GC

步驟1. 調(diào)用子類實(shí)現(xiàn)的成員函數(shù)InitializePhase執(zhí)行GC初始化階段。

步驟2. 獲取用于訪問(wèn)Java堆的鎖。

步驟3. 調(diào)用子類實(shí)現(xiàn)的成員函數(shù)MarkingPhase執(zhí)行GC并行標(biāo)記階段。

步驟4. 釋放用于訪問(wèn)Java堆的鎖。

步驟5. 掛起所有的ART運(yùn)行時(shí)線程。

步驟6. 調(diào)用子類實(shí)現(xiàn)的成員函數(shù)HandleDirtyObjectsPhase處理在GC并行標(biāo)記階段被修改的對(duì)象。。

步驟7. 恢復(fù)第4步掛起的ART運(yùn)行時(shí)線程。

步驟8. 重復(fù)第5到第7步,直到所有在GC并行階段被修改的對(duì)象都處理完成。

步驟9. 獲取用于訪問(wèn)Java堆的鎖。

步驟10. 調(diào)用子類實(shí)現(xiàn)的成員函數(shù)ReclaimPhase執(zhí)行GC回收階段。

步驟11. 釋放用于訪問(wèn)Java堆的鎖。

步驟12. 調(diào)用子類實(shí)現(xiàn)的成員函數(shù)FinishPhase執(zhí)行GC結(jié)束階段。

所以不論是并發(fā)還是非并發(fā),都會(huì)引起stopworld的情況出現(xiàn),并發(fā)的情況下單次stopworld的時(shí)間會(huì)更短,基本區(qū)別和。

3.***rt并發(fā)和Dalvik并發(fā)GC的差異

首先可以通過(guò)如下2張圖來(lái)對(duì)比下

Dalvik GC: 

 

Art GC:  

 

Art的并發(fā)GC和Dalvik的并發(fā)GC有什么區(qū)別呢,初看好像2者差不多,雖然沒(méi)有一直掛起線程,但是也會(huì)有暫停線程去執(zhí)行標(biāo)記對(duì)象的流程。通過(guò)閱讀相關(guān)文檔可以了解到Art并發(fā)GC對(duì)于Dalvik來(lái)說(shuō)主要有三個(gè)優(yōu)勢(shì)點(diǎn):

      1. 標(biāo)記自身

 Art在對(duì)象分配時(shí)會(huì)將新分配的對(duì)象壓入到Heap類的成員變量allocationstack描述的Allocation Stack中去,從而可以一定程度縮減對(duì)象遍歷范圍。

      2. 預(yù)讀取

 對(duì)于標(biāo)記Allocation Stack的內(nèi)存時(shí),會(huì)預(yù)讀取接下來(lái)要遍歷的對(duì)象,同時(shí)再取出來(lái)該對(duì)象后又會(huì)將該對(duì)象引用的其他對(duì)象壓入棧中,直至遍歷完畢。

      3. 減少Pause時(shí)間

在Mark階段是不會(huì)Block其他線程的,這個(gè)階段會(huì)有臟數(shù)據(jù),比如Mark發(fā)現(xiàn)不會(huì)使用的但是這個(gè)時(shí)候又被其他線程使用的數(shù)據(jù),在Mark階段也會(huì)處理一些臟數(shù)據(jù)而不是留在***Block的時(shí)候再去處理,這樣也會(huì)減少后面Block階段對(duì)于臟數(shù)據(jù)的處理的時(shí)間。

3.6 前后臺(tái)GC

前臺(tái)Foreground指的就是應(yīng)用程序在前臺(tái)運(yùn)行時(shí),而后臺(tái)Background就是應(yīng)用程序在后臺(tái)運(yùn)行時(shí)。因此,F(xiàn)oreground GC就是應(yīng)用程序在前臺(tái)運(yùn)行時(shí)執(zhí)行的GC,而Background就是應(yīng)用程序在后臺(tái)運(yùn)行時(shí)執(zhí)行的GC。

應(yīng)用程序在前臺(tái)運(yùn)行時(shí),響應(yīng)性是最重要的,因此也要求執(zhí)行的GC是高效的。相反,應(yīng)用程序在后臺(tái)運(yùn)行時(shí),響應(yīng)性不是最重要的,這時(shí)候就適合用來(lái)解決堆的內(nèi)存碎片問(wèn)題。因此,Mark-Sweep GC適合作為Foreground GC,而Mark-Compact GC適合作為Background GC。

由于有Compact的能力存在,碎片化在Art上可以很好的被避免,這個(gè)也是Art一個(gè)很好的能力。

3.7 Art大法好

總的來(lái)看,art在gc上做的比dalvik好太多了,不光是gc的效率,減少pause時(shí)間,而且還在內(nèi)存分配上對(duì)大內(nèi)存的有單獨(dú)的分配區(qū)域,同時(shí)還能有算法在后臺(tái)做內(nèi)存整理,減少內(nèi)存碎片。對(duì)于開發(fā)者來(lái)說(shuō)art下我們基本可以避免很多類似gc導(dǎo)致的卡頓問(wèn)題了。另外根據(jù)谷歌自己的數(shù)據(jù)來(lái)看,Art相對(duì)Dalvik內(nèi)存分配的效率提高了10倍,GC的效率提高了2-3倍。

4、GC Log

當(dāng)我們想要根據(jù)GC日志來(lái)追查一些GC可能造成的卡頓時(shí),我們需要了解GC日志的組成,不同信息代表了什么含義。

4.1 Dalvik GC日志

dalvik的日志格式基本如下:

  1. D/dalvikvm: <GC_Reason> <Amount_freed>, <Heap_stats>, <Pause_time>, <Total_time> 
  • gc_reason:就是我們上文提到的,是gc_alloc還是gc_concurrent,了解到不同的原因方便我們做不同的處理。
  • amount_freed:表示系統(tǒng)通過(guò)這次GC操作釋放了多少內(nèi)存
  • Heap_stats:中會(huì)顯示當(dāng)前內(nèi)存的空閑比例以及使用情況(活動(dòng)對(duì)象所占內(nèi)存 / 當(dāng)前程序總內(nèi)存)
  • Pause_time:表示這次GC操作導(dǎo)致應(yīng)用程序暫停的時(shí)間。關(guān)于這個(gè)暫停的時(shí)間,在2.3之前GC操作是不能并發(fā)進(jìn)行的,也就是系統(tǒng)正在進(jìn)行GC,那么應(yīng)用程序就只能阻塞住等待GC結(jié)束。而自2.3之后,GC操作改成了并發(fā)的方式進(jìn)行,就是說(shuō)GC的過(guò)程中不會(huì)影響到應(yīng)用程序的正常運(yùn)行,但是在GC操作的開始和結(jié)束的時(shí)候會(huì)短暫阻塞一段時(shí)間,所以還有后續(xù)的一個(gè)total_time。
  • Total_time : 表示本次GC所花費(fèi)的總時(shí)間和上面的Pause_time,也就是stop all是不一樣的,卡頓時(shí)間主要看上面的pause_time。

4.2 Art GC日志

  1. I/art: <GC_Reason> <Amount_freed>, <LOS_Space_Status>, <Heap_stats>, <Pause_time>, <Total_time> 

基本情況和Dalvik沒(méi)有什么差別,GC的Reason更多了,還多了一個(gè)OS_Space_Status

  • LOS_Space_Status:Large Object Space,大對(duì)象占用的空間,這部分內(nèi)存并不是分配在堆上的,但仍屬于應(yīng)用程序內(nèi)存空間,主要用來(lái)管理 bitmap 等占內(nèi)存大的對(duì)象,避免因分配大內(nèi)存導(dǎo)致堆頻繁 GC。

寫在***:圖片來(lái)源自網(wǎng)絡(luò),特別鳴謝老羅。 

責(zé)任編輯:龐桂玉 來(lái)源: 騰訊Bugly
相關(guān)推薦

2022-02-15 11:49:08

eBPFGo內(nèi)存

2019-11-27 14:41:50

Java技術(shù)語(yǔ)言

2021-10-27 16:52:37

LayoutInfl源碼解析

2010-09-16 14:42:44

JVM

2019-01-10 08:24:06

2014-04-02 17:10:00

虛擬應(yīng)用工作原理

2023-08-31 08:12:23

應(yīng)用場(chǎng)景業(yè)務(wù)異常HTTP

2011-03-11 09:41:17

JavaGC

2010-09-15 15:59:11

CSS hack

2017-08-09 08:56:04

SP存儲(chǔ)Android

2024-12-17 08:28:30

2024-08-28 08:00:00

2010-09-29 14:54:34

J2MEHashtable

2019-09-02 14:53:53

JVM內(nèi)存布局GC

2017-01-15 17:34:08

2022-10-30 15:00:50

2009-06-15 10:43:45

Java程序員Java程序GC

2022-01-25 09:15:39

V8垃圾回收算法

2023-05-08 14:56:00

Kafka高可靠高性能

2022-06-20 05:59:35

5G技術(shù)音視頻技術(shù)安卓系統(tǒng)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

日韩午夜免费| 国产手机视频一区二区| av在线视屏| 日本亚洲欧洲色α| 高端美女服务在线视频播放| 色综合久久久久久久久| 毛片在线播放网址| 黑人巨大精品欧美一区二区| 黄页网站免费在线观看| 欧洲亚洲精品在线| 91精品麻豆| 国产精品我不卡| 欧美激情一区二区在线| 神马久久久久| 久久福利网址导航| 亚洲清纯自拍| 国内精品久久久久久野外| 久久夜色精品国产欧美乱| 日韩电影在线观看电影| 激情都市亚洲| 午夜3点看的视频| 日本精品视频在线播放| 亚洲国产高清一区二区三区| 欧美欧美欧美| 欧美重口另类videos人妖| 久久久精品国产免费观看同学| sm性调教片在线观看| 日韩国产一级片| 久热精品视频在线观看一区| 久久久99精品免费观看不卡| 视频二区欧美毛片免费观看| 黑巨人与欧美精品一区| 国产精品女视频| 欧美怡红院视频| 日韩高清欧美激情| 欧美www.| 免费在线观看的毛片| 麻豆中文字幕在线观看| 精品三级在线观看| 自拍偷拍欧美一区| 三级在线播放| 91成人在线播放| 国产成人综合一区| **欧美日韩vr在线| 国产丝袜欧美中文另类| 久久免费国产| 成人免费毛片app| 久久99日本精品| 亚洲欧美不卡| 日日夜夜精品网站| 51视频国产精品一区二区| 欧美丰满嫩嫩电影| 日韩欧美大尺度| 国产精品77777竹菊影视小说| 美日韩中文字幕| 欧美大片网站| 一级一片免费视频| 1024视频在线| 欧美日韩精品免费观看视一区二区| 日韩视频免费观看高清完整版在线观看 | 国产超碰在线观看| 国产成a人亚洲精v品在线观看| 99久re热视频这里只有精品6| 在线这里只有精品| 欧美欧美全黄| bl视频在线免费观看| 精品国产综合区久久久久久| 天天影视色香欲综合网老头| 成人资源在线播放| av在线第一页| 91青草视频久久| 欧美日韩一区自拍| 综合日韩av| 欧美一级片免费播放| 91成人在线视频| 欧美大片免费观看| 欧美国产丝袜视频| 亚洲欧美成人vr| 欧美黄色小说| 天堂av一区二区| 美女啪啪无遮挡免费久久网站| 国产精品第13页| 综合久久婷婷| 毛片大全在线观看| 久久久久久久少妇| 欧美一区二区三区白人| 久久精品一级爱片| 国产精品一区二区不卡| 另类尿喷潮videofree| 欧美日韩不卡| 日韩另类在线| 黄色网页在线观看| 91国产精品视频在线观看| 人偷久久久久久久偷女厕| 国产精品高潮在线| 欧美人与物videos| 91精品国产高清一区二区三区蜜臀| 欧美变态挠脚心| 大片免费在线观看| 国产又粗又长又大的视频| 99精品一区二区三区的区别| 亚洲不卡中文字幕| 久久久综合免费视频| 国产91aaa| 乱人伦xxxx国语对白| 美丽的姑娘在线观看免费动漫| 免费毛片b在线观看| 成人免费在线观看| 欧产日产国产精品视频 | 欧美午夜一区二区| 久久久xxx| 免费成人网www| 亚洲影视在线| 亚洲精品久久久蜜桃| 色综合久久九月婷婷色综合| 福利片在线观看| h色视频在线观看| 在线丝袜欧美日韩制服| www.99久久热国产日韩欧美.com | 久草精品在线播放| 污网站视频在线观看| 成人性生活视频| 成人影院在线| 国产乱国产乱300精品| 一区二区欧美国产| 欧美一区二区三区色| 日韩免费观看视频| avove在线观看| 亚洲精品一区二区| www国产在线观看| 国产欧美亚洲精品a| 国产一区美女在线| 在线观看亚洲一区| 国产精品入口夜色视频大尺度 | 欧美视频精品一区| 欧美激情中文字幕一区二区| 久久久亚洲欧洲日产国码αv| 极品尤物av久久免费看| 国产一区在线不卡| 日韩av二区在线播放| 成人一二三区视频| 久久66热re国产| 国产精品视频在线看| 精品电影一区二区| 韩国成人av| 永久免费精品视频网站| 成人美女免费网站视频| 91福利视频在线观看| 国产aⅴ夜夜欢一区二区三区 | 成人在线观看91| 国产精品青草久久久久福利99| 欧美日韩一区二区视频在线| 亚洲色图38p| 国产最新视频在线观看| 乱人伦中文视频在线| 成人精品国产| 国产久一一精品| 国产精品色在线| 日韩国产精品一区| 一区二区三区视频在线观看 | www.男人天堂网| 2018日韩中文字幕| 久久久久久免费精品| 国产精品久久久av| 久久久精品2019中文字幕之3| 91在线导航| 亚洲精品免费在线播放| 成人免费视频国产在线观看| 色呦呦在线观看视频| 精品国产乱码久久久久软件| 久久精品在线观看| 成人精品在线| 国产精品狼人久久影院观看方式| 久久一卡二卡| 欧美激情精品久久久| 国产美女主播一区| 麻豆md0077饥渴少妇| 成人在线免费电影网站| www国产精品av| 国产91在线播放| 久草在线免费福利资源| 国内精品伊人久久久久影院对白| 国产午夜精品一区二区三区| 国产l精品国产亚洲区久久| 欧美jizz19性欧美| 欧美午夜片在线免费观看| 中国一区二区三区| 一区二区三区欧美| 国产一区二区精品在线| 色呦呦在线视频| 中文字幕中文在线不卡住| av成人在线电影| 粉嫩一区二区三区四区公司1| 日韩欧亚中文在线| 欧美 国产 精品| 午夜精品一区二区三区国产 | 亚洲美女一区| 久久久久免费精品国产| 九色porny丨首页入口在线| 精品久久久久久国产91|