GC那些事兒--Android內(nèi)存優(yōu)化第一彈

內(nèi)容太晦澀店枣,先樂(lè)一個(gè)

引言

App優(yōu)化之內(nèi)存優(yōu)化(序), 作為App優(yōu)化系列中內(nèi)存優(yōu)化的一個(gè)小部分.

由于內(nèi)存相關(guān)知識(shí)比較生澀, 內(nèi)存優(yōu)化中使用到的相關(guān)工具, 也有很多專有名詞. 對(duì)Java內(nèi)存管理, GC, Android內(nèi)存管理, Dalvik/ART等知識(shí)有一個(gè)理論的認(rèn)識(shí), 可以讓我們更好的使用這些工具, 分析內(nèi)存問(wèn)題.

據(jù)此, 我們就先從理論入手, 聊聊GC那些事兒.

1, 何為GC

GC 是 garbage collection 的縮寫(xiě), 垃圾回收的意思. 也可以是 Garbage Collector, 也就是垃圾回收器.

1.1 垃圾回收器

我們先來(lái)解釋下Garbage Collector(垃圾回收器).

內(nèi)存管理, 一直是編程中的一個(gè)大的問(wèn)題. 在較老的語(yǔ)言中, 例如C++語(yǔ)言中, 內(nèi)存管理是顯式的, 也就是說(shuō)使用者自己申請(qǐng)內(nèi)存使用, 自己釋放內(nèi)存. 這就是為什么C++語(yǔ)言中除了構(gòu)造函數(shù), 還有析構(gòu)函數(shù). 我們?cè)趧?chuàng)建對(duì)象的時(shí)候調(diào)用構(gòu)造函數(shù)創(chuàng)建, 系統(tǒng)會(huì)在對(duì)象結(jié)束其作用域的時(shí)候調(diào)用析構(gòu)函數(shù), 我們需要做的就是在析構(gòu)函數(shù)中釋放掉我們申請(qǐng)的相關(guān)資源, 以便釋放內(nèi)存地址.

顯然, 這種顯式的由編程人員自己控制釋放內(nèi)存的方式很容易出問(wèn)題, 忘了, 漏了, 都可能導(dǎo)致內(nèi)存問(wèn)題. 也不符合程序員要懶的特征.

故而, Java語(yǔ)言中引入了自動(dòng)內(nèi)存管理的機(jī)制, 也就是垃圾回收器. 大部分的現(xiàn)代面向?qū)ο笳Z(yǔ)言, 也都是采用自動(dòng)內(nèi)存管理機(jī)制.

內(nèi)存自動(dòng)管理回收機(jī)制可以解決大部分, 但不是所有的內(nèi)存問(wèn)題, 這也是為什么我們要討論內(nèi)存泄露.

垃圾回收器的職責(zé)

垃圾回收器有三大職責(zé):

  1. 分配內(nèi)存;
  2. 確保任何被引用的對(duì)象保留在內(nèi)存中;
  3. 回收不能通過(guò)引用關(guān)系找到的對(duì)象的內(nèi)存.

垃圾回收的一般流程

gc process

1.2 相關(guān)概念

垃圾回收(GC)

垃圾回收器中有一個(gè)進(jìn)程來(lái)做上面的這些事情, 這個(gè)進(jìn)程查找我們的對(duì)象引用的關(guān)系并釋放其內(nèi)存, 這個(gè)進(jìn)程就是garbage collection(垃圾回收), 也就是我們常說(shuō)的GC.

Heap和Stack

簡(jiǎn)單說(shuō)下:

  • Heap內(nèi)存是指java運(yùn)行環(huán)境用來(lái)分配給對(duì)象和JRE類(lèi)的內(nèi)存. 是應(yīng)用的內(nèi)存空間.
  • Stack內(nèi)存是相對(duì)于線程Thread而言的, 它保存線程中方法中短期存在的變量值和對(duì)Heap中對(duì)象的引用等.
  • Stack內(nèi)存, 顧名思義, 是類(lèi)Stack方式, 總是后進(jìn)先出(LIFO)的.
  • 我們通常說(shuō)的GC的針對(duì)Heap內(nèi)存的. 因?yàn)镾tack內(nèi)存相當(dāng)于是隨用隨銷(xiāo)的.
heap&stack

GC Root

直譯GC根, 我們姑且不譯了吧.
所謂GC Root我們可以理解為是一個(gè)Heap內(nèi)存之外的對(duì)象, 通常包括但不僅限于如下幾種:

  • System Class 系統(tǒng)Class Loader加載的類(lèi). 例如java運(yùn)行環(huán)境中rt.jar中類(lèi), 比如java.util.* package中的類(lèi).
  • Thread 運(yùn)行中的線程
  • JNI 中的本地/全局變量, 用戶自定義的JNI代碼或是JVM內(nèi)部的.
  • Busy Monitor 任何調(diào)用了wait()或notify()方法, 或是同步化的(synchronized)的東西. 可以理解為同步監(jiān)控器.
  • Java本地實(shí)例, 還在運(yùn)行的Thread的stack中的方法創(chuàng)建的對(duì)象.

活對(duì)象/垃圾

如果這個(gè)對(duì)象是引用可達(dá)的, 則稱之為活的(live), 反之, 如果這個(gè)對(duì)象引用不可達(dá), 則稱之為死的(dead), 也可以稱之為垃圾(garbage).

這個(gè)引用可達(dá)與不可達(dá)就是相對(duì)于GC Root來(lái)說(shuō)的:

gc-roots

2, Java的內(nèi)存管理機(jī)制

2.1 關(guān)于JVM

我們平常在查看我們的java版本時(shí), 你會(huì)發(fā)現(xiàn):

$ java -version
java version "1.8.0_74"
Java(TM) SE Runtime Environment (build 1.8.0_74-b02)
Java HotSpot(TM) 64-Bit Server VM (build 25.74-b02, mixed mode)

其中有個(gè)HotSpot VM的東西, 那么這個(gè)是什么呢? 和JVM有什么關(guān)系呢?

在此簡(jiǎn)單說(shuō)下, 以便行文:

  • JVM, Java虛擬機(jī), 可以簡(jiǎn)單理解為一種技術(shù)思想, 虛擬技術(shù)理念.
  • HotSpot VM是JVM的一種實(shí)現(xiàn), 包含了服務(wù)器版和桌面應(yīng)用程序版, 現(xiàn)時(shí)由Oracle維護(hù)并發(fā)布.

我們當(dāng)前使用的sun(oracle)的java版本(應(yīng)該是1.3以上)都是內(nèi)置的HotSpot VM實(shí)現(xiàn). 所以接下來(lái)的分析也都是基于HotSpot VM的, 但是還是簡(jiǎn)稱JVM.

2.2 JVM內(nèi)存區(qū)域

JVM使用分代式的內(nèi)存管理方式, 將Heap分成三代 --- 新生代, 老一代, 持久代.

Hotspot heap structure
  • Young Generation

    • 新生代.
    • 所有new的對(duì)象.
    • 該區(qū)域的內(nèi)存管理使用minor garbage collection(小GC).
    • 更進(jìn)一步分成Eden space, Survivor 0 和 Survivor 1 三個(gè)部分.
  • Old Generation

    • 老年區(qū).
    • 新生代中執(zhí)行小粒度的GC幸存下來(lái)的"老"對(duì)象.
    • 該區(qū)域的內(nèi)存管理使用major garbage collection(大GC).
  • Permanent Generation

    • 持久代.
    • 包含應(yīng)用的類(lèi)/方法信息, 以及JRE庫(kù)的類(lèi)和方法信息.

小GC執(zhí)行非常頻繁, 而且速度特別快.
大GC一般會(huì)比小GC慢十倍以上.
大小GC都會(huì)發(fā)出"Stop the World"事件, 也就是說(shuō)中斷程序運(yùn)行, 直至GC完成. 這也是我們?cè)?a href="http://www.reibang.com/p/1fb065c806e6" target="_blank">App優(yōu)化之消除卡頓中為什么說(shuō)頻繁GC會(huì)造成用戶感知卡頓.

3, GC的流程

了解了內(nèi)存Heap的幾個(gè)區(qū)域, 我們?cè)賮?lái)看下垃圾收集器是怎么利用這幾個(gè)區(qū)域來(lái)管理內(nèi)存和回收垃圾的.

1. 創(chuàng)建新的對(duì)象

每當(dāng)我們使用new創(chuàng)建一個(gè)對(duì)象時(shí), 這個(gè)對(duì)象會(huì)被分配到新生代Eden區(qū)域:

object allocation

2. 當(dāng)Eden區(qū)域滿時(shí)
當(dāng)Eden區(qū)域內(nèi)存被分配完時(shí), 小GC程序被觸發(fā):

Eden filling

引用可達(dá)的對(duì)象會(huì)移到Survivor(幸存者)區(qū)域--S0, 然后清空Eden區(qū)域, 此時(shí)引用不可達(dá)的對(duì)象會(huì)直接刪除, 內(nèi)存回收, 如下:

aged

3. Eden再次滿時(shí)
當(dāng)Eden區(qū)域再次分配完后, 小GC執(zhí)行, 引用可達(dá)的對(duì)象會(huì)移到Survivor(幸存者)區(qū)域, 而引用不可達(dá)的對(duì)象會(huì)跟隨Eden的清空而刪除回收.

需要注意的是, 這次引用可達(dá)的對(duì)象移動(dòng)到的是S1的幸存者區(qū).
而且, S0區(qū)域也會(huì)執(zhí)行小GC, 將其中還引用可達(dá)的對(duì)象移動(dòng)到S1區(qū), 且年齡+1. 然后清空S0, 回收其中引用不可達(dá)的對(duì)象.

此時(shí), 所有引用可達(dá)的對(duì)象都在S1區(qū), 且S1區(qū)的對(duì)象存在不同的年齡. 如下:

next filling

當(dāng)Eden第三次滿時(shí), S0和S1的角色互換了:

s0s1

依此循環(huán).

4. 當(dāng)Survivor區(qū)的對(duì)象年齡達(dá)到"老年線"時(shí)
上面1~3循環(huán), Survivor區(qū)的對(duì)象年齡也會(huì)持續(xù)增長(zhǎng), 當(dāng)其中某些對(duì)象年齡達(dá)到"老年線", 例如8歲時(shí), 它們會(huì)"晉升"到老年區(qū).

old aged

如此1~4步重復(fù), 大體流程是這樣的

gc flow

參考


轉(zhuǎn)載請(qǐng)注明出處, 歡迎大家分享到朋友圈, 微博~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末馍资,一起剝皮案震驚了整個(gè)濱河市倦沧,隨后出現(xiàn)的幾起案子喳整,更是在濱河造成了極大的恐慌齐媒,老刑警劉巖每篷,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件篇裁,死亡現(xiàn)場(chǎng)離奇詭異菲饼,居然都是意外死亡让腹,警方通過(guò)查閱死者的電腦和手機(jī)远剩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)骇窍,“玉大人瓜晤,你說(shuō)我怎么就攤上這事「鼓桑” “怎么了痢掠?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)嘲恍。 經(jīng)常有香客問(wèn)我足画,道長(zhǎng),這世上最難降的妖魔是什么佃牛? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任淹辞,我火速辦了婚禮,結(jié)果婚禮上俘侠,老公的妹妹穿的比我還像新娘象缀。我一直安慰自己彬向,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布攻冷。 她就那樣靜靜地躺著,像睡著了一般遍希。 火紅的嫁衣襯著肌膚如雪等曼。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,365評(píng)論 1 302
  • 那天凿蒜,我揣著相機(jī)與錄音禁谦,去河邊找鬼。 笑死废封,一個(gè)胖子當(dāng)著我的面吹牛州泊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播漂洋,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼遥皂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了刽漂?” 一聲冷哼從身側(cè)響起演训,我...
    開(kāi)封第一講書(shū)人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贝咙,沒(méi)想到半個(gè)月后样悟,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡庭猩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年窟她,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蔼水。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡震糖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出徙缴,到底是詐尸還是另有隱情试伙,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布于样,位于F島的核電站疏叨,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏穿剖。R本人自食惡果不足惜蚤蔓,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望糊余。 院中可真熱鬧秀又,春花似錦单寂、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至昏苏,卻和暖如春尊沸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贤惯。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工洼专, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人孵构。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓屁商,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親颈墅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蜡镶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容