第三章 垃圾收集器與內存分配策略

GC三件事

  • 哪些內存需要回收
  • 何時回收
  • 怎么回收

主要考慮的是方法區

如何判斷對象已死

1、引用計數:實現簡單,教科書答案,java虛擬機沒有采用

2、根搜索算法:

基本思路就是通過一系列名為"GC Roots"的對象作為起始點,從這些節點開始向下搜索,搜索所走過的路徑稱為引用鏈(Reference Chain),當一個對象到GC Roots沒有任何引用鏈相連時,則證明此對象是不可用的。

3、java里面可以作為GCRoots的對象:

a.虛擬機棧(棧楨中的本地變量表)中的引用的對象

b.方法區中的類靜態屬性引用的對象

c.方法區中的常量引用的對象

d.本地方法棧中JNI的引用的對象

4、如何判斷一個對象已死

  • 該類所有的實例都已經被回收,也就是Java堆中不存在該類的任何實例。
  • 加載該類的ClassLoader已經被回收。
  • 該類對應的java.lang.Class對象沒有在任何地方被引用,無法在任何地方通過反射訪問該
    類的方法

5、垃圾收集算法

算法名稱 英文名 描述 優點 缺點
標記-清除 Mark-Sweep 算法分為“標記”和“清除”兩個階段:首先標記出所有需要回收的對象,在標記完成后統一回收所有被標記的對象 1、效率不高;2、內存碎片,效率不高
復制算法 Copying 將內存分為一塊較大的Eden空間和兩塊較小的Survivor空間,8:1,內存利用率90% 解決了效率問題【適合新生代】 利用率低了
標記-整理 Mark-Compact 標記過程仍然與“標記-清除”算法一樣,但后續步驟不是直接對可回收對象進行清理,而是讓所有存活的對象都向一端移動,然后直接清理掉端邊界以外的內存 減少復制,減少空間浪費
分代收集算法 Generational Collection 根據對象存活周期的不同將內存劃分為幾塊。一般為新生代和老生代,新生代采用復制算法,老生代采用標記-清除 或是 標記-整理

6、垃圾收集器

如果說收集算法是內存回收的方法論,那么垃圾收集器就是內存回收的具體實現
HotSpot虛擬機的垃圾收集器

名字 新\老 生代 原理 優點 缺點 備注
Serial收集器 復制算法;收集器是一個單線程的收集器;必須暫停其他所有的工作線程,直到它收集結束 簡單而高效,少了線程交互開銷 Stop The World Client模式下的虛擬機新生代默認選擇
ParNew收集器 ParNew收集器其實就是Serial收集器的多線程版本 多線程 單CPU還不如Serial收集器 是許多運行在Server模式下的虛擬機中首選的新生代收集器,其中有一個與性能無關但很重要的原因是,除了Serial收集器外,目前只有它能與CMS收集器配合工作
Parallel Scavenge收集器 Parallel Scavenge收集器的目標則是達到一個可控制的吞吐量(Throughput)。所謂吞吐量就是CPU用于運行用戶代碼的時間與CPU總消耗時間的比值,即吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間) 復制算法;并行
Serial Old收集器 使用“標記-整理”算法
Parallel Old收集器 Parallel Scavenge收集器的老年代版本,使用多線程和“標記-整理”算法
CMS收集器(Concurrent Mark Sweep) CMS收集器是基于“標記—清除”算法實現的

并行(Parallel):指多條垃圾收集線程并行工作,但此時用戶線程仍然處于等待狀
態。

并發(Concurrent):指用戶線程與垃圾收集線程同時執行(但不一定是并行的,可能
會交替執行),用戶程序在繼續運行,而垃圾收集程序運行于另一個CPU上。

7、理解GC日志

2017-03-24T11:18:49.803+0800: 311976.229: [GC (Allocation Failure) 2017-03-24T11:18:49.803+0800: 311976.229: [ParNew: 1428004K->26220K(1485504K), 0.0369712 secs] 3356779K->1955081K(5155520K), 0.0373455 secs] [Times: user=0.13 sys=0.00, real=0.04 secs]

2017-03-24T11:18:49.803+0800:【1】 311976.229:【2】 [GC【3】 (Allocation Failure【4】) 2017-03-24T11:18:49.803+0800: 311976.229: [ParNew:【5】 1428004K->26220K【6】 (1485504K【7】), 0.0369712 secs【8】] 3356779K->1955081K【9】(5155520K【10】), 0.0373455 secs【11】] [Times: user=0.13 sys=0.00, real=0.04 secs【12】]

詳解:

  • 2017-03-24T11:18:49.803+0800【1】GC事件(GC event)開始的時間點
  • 311976.229:【2】GC時間的開始時間,相對于JVM的啟動時間,單位是秒(Measured in seconds)
  • GC 【3】用來區分(distinguish)是 Minor GC 還是 Full GC 的標志(Flag). 這里的 GC 表明本次發生的是 Minor GC.
  • Allocation Failure 【4】引起垃圾回收的原因. 本次GC是因為年輕代中沒有任何合適的區域能夠存放需要分配的數據結構而觸發的.
  • ParNew: 【5】使用的垃圾收集器的名字
  • 1428004K->26220K 【6】在本次垃圾收集之前和之后的年輕代內存使用情況(Usage)
  • 1485504K 【7】年輕代的總的大小(Total size).
  • 0.0369712 secs【8】該內存區域GC所占用的時間,單位是秒
  • 3356779K->1955081K 【9】在本次垃圾收集之前和之后整個堆內存的使用情況(Total used heap)
  • 5155520K 【10】總的可用的堆內存(Total available heap).
  • 0.0373455 secs【11】GC事件的持續時間(Duration),單位是秒
  • Times: user=0.13 sys=0.00, real=0.04 secs 【12】這里面的user、
    sys和real與Linux的time命令所輸出的時間含義一致,分別代表用戶態消耗的CPU時間、內核 態消耗的CPU事件和操作從開始到結束所經過的墻鐘時間(Wall Clock Time)。CPU時間與
    墻鐘時間的區別是,墻鐘時間包括各種非運算的等待耗時.

8、內存分配與回收策略

  • 對象優先在Eden分配
package study3;

/**
 *
 * -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
 * @date 2017/03/24
 */
public class TestAllocation {
    public static void main(String[] args) {
        final int _1MB = 1024 * 1024;
        byte[] allocation1, allocation2, allocation3, allocation4;
        allocation1 = new byte[2 * _1MB];
        allocation2 = new byte[2 * _1MB];
        allocation3 = new byte[2 * _1MB];
        // 出現一次Minor GC
        allocation4 = new byte[4 * _1MB];
    }
}

[GC [ParNew: 8118K->473K(9216K), 0.0075132 secs] 8118K->473K(19456K), 0.0086882 secs] [Times: user=0.00 sys=0.01, real=0.01 secs] 
Heap
 par new generation   total 9216K, used 4981K [7f9a00000, 7fa400000, 7fa400000)
  eden space 8192K,  55% used [7f9a00000, 7f9e66db0, 7fa200000)
  from space 1024K,  46% used [7fa300000, 7fa3767f0, 7fa400000)
  to   space 1024K,   0% used [7fa200000, 7fa200000, 7fa300000)
 concurrent mark-sweep generation total 10240K, used 0K [7fa400000, 7fae00000, 7fae00000)
 concurrent-mark-sweep perm gen total 21248K, used 4898K [7fae00000, 7fc2c0000, 800000000)
  • 大對象直接進入老年代
  • 長期存活的對象將進入老年代
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,885評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,312評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,993評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,667評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,410評論 6 411
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,778評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,775評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,955評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,521評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,266評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,468評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,998評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,696評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,095評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,385評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,193評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,431評論 2 378

推薦閱讀更多精彩內容