
1、Young Generation
新生代的內(nèi)存區(qū)域又被分成三部分,分別是Eden、s0、s1,在hotspot中它們的默認(rèn)是比例是8:1:1,為什么是這個(gè)比例下面會(huì)解釋。每次分配新對(duì)象都是從Eden中分配,新生代的gc過(guò)程是,通過(guò)gc root對(duì)象(gc root對(duì)象包括:在棧幀中的對(duì)象、native棧中的對(duì)象、靜態(tài)對(duì)象)標(biāo)記存活的對(duì)象,并且把存活的對(duì)象拷貝到s0中然后清空Eden,接下來(lái)的gc又會(huì)把Eden和s0存活的對(duì)象拷貝到s1中,s0和是s1總有一個(gè)是空閑的,gc過(guò)程就是把Eden和其中一個(gè)s的存活對(duì)象拷貝到另一個(gè)s中,然后清空s和Eden。為什么Eden:s0:s1是8:1:1呢?那是因?yàn)樾律鷮?duì)象經(jīng)過(guò)一次gc后存活的概率只有5%左右,之前IBM統(tǒng)計(jì)過(guò),正是因?yàn)樾律?jīng)過(guò)gc后存活的對(duì)象很少,才會(huì)使用拷貝擦除這種方法。gc最快的方法就是把沒(méi)有被gc root對(duì)象直接引用或者間接引用的對(duì)象標(biāo)記為無(wú)效,但是這樣勢(shì)必會(huì)造成大量的內(nèi)存碎片,所以綜合考慮最終在新生代使用拷貝擦除這種算法
2、Old Generation
在新生代中經(jīng)過(guò)多次gc后仍然存活的對(duì)象則會(huì)晉升為老年代對(duì)象。老年代對(duì)象的gc比新生代更耗時(shí)。
老年代的gc過(guò)程是:
先從gc root對(duì)象出發(fā),標(biāo)記能被gc root對(duì)象直接引用或者間接引用的對(duì)象為存活的
把存活的對(duì)象移到內(nèi)存區(qū)域的一端并對(duì)齊,然后清空未標(biāo)記為存活的對(duì)象。在老年代區(qū)域中,gc后對(duì)象的存活的幾率會(huì)比較大,所以一般不用拷貝擦除的方法來(lái)回收對(duì)象,如果使用拷貝擦除的方法的話需要進(jìn)行大量的拷貝工作效率肯定不高,而且還必須要有一塊空閑的內(nèi)存用來(lái)存放存活的對(duì)象,這樣勢(shì)必也會(huì)造成內(nèi)存的利用率不高
3、Android內(nèi)存回收的特點(diǎn)
由于Android作為一個(gè)終端,需要快速的響應(yīng)用戶的操作,而gc過(guò)程又要暫停所有的線程,所以必須要保證的gc的時(shí)間不會(huì)太長(zhǎng)。在Android中應(yīng)用啟動(dòng)的時(shí)候一般會(huì)分配一段內(nèi)存作為初始內(nèi)存,在應(yīng)用的運(yùn)行過(guò)程需要?jiǎng)?chuàng)建一個(gè)新對(duì)象,而初始分配的內(nèi)存空間已經(jīng)無(wú)法提供足夠的內(nèi)存,此時(shí)就會(huì)觸發(fā)gc,如果gc過(guò)后還是沒(méi)有足夠內(nèi)存則會(huì)對(duì)堆內(nèi)存進(jìn)行擴(kuò)容,擴(kuò)容到最大值后還是沒(méi)有提供足夠的內(nèi)存則會(huì)再進(jìn)行一次gc,這次gc會(huì)把軟引用也清空,如果仍然沒(méi)有足夠的內(nèi)存就拋出oom。
總結(jié)起來(lái)Android系統(tǒng)不會(huì)一次性就把堆內(nèi)存分配給應(yīng)用進(jìn)程,這樣會(huì)導(dǎo)致gc的時(shí)間很長(zhǎng),用戶的操作長(zhǎng)時(shí)間得不到響應(yīng),而是分步給應(yīng)用進(jìn)程的堆內(nèi)存進(jìn)行擴(kuò)容直到最大限制值