垃圾收集器
如果說收集算法是內(nèi)存回收的方法論, 那垃圾收集器就是內(nèi)存回收的實(shí)踐者舌劳⊙薪校《Java虛擬機(jī)規(guī)范》 中對(duì)垃圾收集器應(yīng)該如何實(shí)現(xiàn)并沒有做出任何規(guī)定, 因此不同的廠商关面、 不同版本的虛擬機(jī)所包含的垃圾收集器都可能會(huì)有很大差別坦袍, 不同的虛擬機(jī)一般也都會(huì)提供各種參數(shù)供用戶根據(jù)自己的應(yīng)用特點(diǎn)和要求組合出各個(gè)內(nèi)存分代所使用的收集器。
1.Serial收集器
Serial收集器是最基礎(chǔ)等太、 歷史最悠久的收集器捂齐, 曾經(jīng)(在JDK 1.3.1之前) 是HotSpot虛擬機(jī)新生代收集器的唯一選擇。大家只看名字就能夠猜到澈驼, 這個(gè)收集器是一個(gè)單線程工作的收集器辛燥, 但它的“單線程”的意義并不僅僅是說明它只會(huì)使用一個(gè)處理器或一條收集線程去完成垃圾收集工作, 更重要的是強(qiáng)調(diào)在它進(jìn)行垃圾收集時(shí)缝其, 必須暫停其他所有工作線程挎塌, 直到它收集結(jié)束。
“Stop The World”這個(gè)詞語也許聽起來很酷内边, 但這項(xiàng)工作是由虛擬機(jī)在后臺(tái)自動(dòng)發(fā)起和自動(dòng)完成的榴都, 在用戶不可知、 不可控的情況下把用戶的正常工作的線程全部停掉漠其, 這對(duì)很多應(yīng)用來說都是不能接受的嘴高。讀者不妨試想一下竿音, 要是你的電腦每運(yùn)行一個(gè)小時(shí)就會(huì)暫停響應(yīng)五分鐘, 你會(huì)有什么樣的心情拴驮?
下圖體現(xiàn)了Serial/Serial Old收集器的運(yùn)行過程 :
對(duì)于“Stop The World”帶給用戶的惡劣體驗(yàn)春瞬, 早期HotSpot虛擬機(jī)的設(shè)計(jì)者們表示完全理解, 但也同時(shí)表示非常委屈:“你媽媽在給你打掃房間的時(shí)候套啤, 肯定也會(huì)讓你老老實(shí)實(shí)地在椅子上或者房間外待著宽气, 如果她一邊打掃, 你一邊亂扔紙屑潜沦, 這房間還能打掃完萄涯?”這確實(shí)是一個(gè)合情合理的矛盾, 雖然垃圾收集這項(xiàng)工作聽起來和打掃房間屬于一個(gè)工種唆鸡, 但實(shí)際上肯定還要比打掃房間復(fù)雜得多涝影!
從JDK 1.3開始, 一直到現(xiàn)在最新的JDK 13争占, HotSpot虛擬機(jī)開發(fā)團(tuán)隊(duì)為消除或者降低用戶線程因垃圾收集而導(dǎo)致停頓的努力一直持續(xù)進(jìn)行著燃逻, 從Serial收集器到Parallel收集器, 再到Concurrent Mark Sweep(CMS) 和Garbage First(G1) 收集器臂痕, 最終至現(xiàn)在垃圾收集器的最前沿成果Shenandoah和ZGC 等唆樊, 我們看到了一個(gè)個(gè)越來越構(gòu)思精巧, 越來越優(yōu)秀刻蟹, 也越來越復(fù)雜的垃圾收集器不斷涌現(xiàn), 用戶線程的停頓時(shí)間在持續(xù)縮短嘿辟, 但是仍然沒有辦法徹底消除(這里不去討論RTSJ中的收集器) 舆瘪, 探索更優(yōu)秀垃圾收集器的工作仍在繼續(xù)。
對(duì)于單核處理器或處理器核心數(shù)較少的環(huán)境來說红伦, Serial收集器由于沒有線程交互的開銷英古, 專心做垃圾收集自然可以獲得最高的單線程收集效率。在用戶桌面的應(yīng)用場(chǎng)景以及近年來流行的部分微服務(wù)應(yīng)用中昙读, 分配給虛擬機(jī)管理的內(nèi)存一般來說并不會(huì)特別大召调, 收集幾十兆甚至一兩百兆的新生代(僅僅是指新生代使用的內(nèi)存, 桌面應(yīng)用甚少超過這個(gè)容量) 蛮浑, 垃圾收集的停頓時(shí)間完全可以控制在十幾唠叛、 幾十毫秒, 最多一百多毫秒以內(nèi)沮稚, 只要不是頻繁發(fā)生收集艺沼, 這點(diǎn)停頓時(shí)間對(duì)許多用戶來說是完全可以接受的。所以蕴掏,Serial收集器對(duì)于運(yùn)行在客戶端模式下的虛擬機(jī)來說是一個(gè)很好的選擇障般。
2.ParNew收集器
在過去多年里调鲸,假設(shè)沒有最新的G1垃圾回收器的話,通常線上系統(tǒng)都是ParNew垃圾回收器作為新生代的垃圾回收器挽荡,當(dāng)然現(xiàn)在即使有了G1藐石,其實(shí)很多線上系統(tǒng)還是用的ParNew。
我們運(yùn)行在服務(wù)器上的Java系統(tǒng)定拟,其實(shí)可以充分利用服務(wù)器的多核CPU資源的優(yōu)勢(shì)于微,比如通常服務(wù)器配置為4核CPU,如果我們使用Serial收集器單線程進(jìn)行垃圾回收办素,是沒有充分利用我們的CPU資源的角雷。如下圖:
根據(jù)上圖我們也可以看出,當(dāng)系統(tǒng)程序停止運(yùn)行后性穿,僅一個(gè)垃圾回收線程在工作勺三,這個(gè)時(shí)候的多核CPU資源沒有得到充分利用,因此我們的ParNew垃圾回收器主打的就是多線程垃圾回收機(jī)制需曾,除了同時(shí)使用多條線程進(jìn)行垃圾收集之外吗坚, 其余的行為包括Serial收集器可用的所有控制參數(shù)(例如:-XX:SurvivorRatio、 -XX:PretenureSizeThreshold呆万、 -XX:HandlePromotionFailure等) 商源、 收集算法、 Stop The World谋减、 對(duì)象分配規(guī)則牡彻、 回收策略等都與Serial收集器完全一致, 在實(shí)現(xiàn)上這兩種收集器也共用了相當(dāng)多的代碼出爹。
ParNew收集器的運(yùn)行圖如下:
ParNew收集器一旦在合適的時(shí)機(jī)執(zhí)行Minor GC的時(shí)候庄吼,就會(huì)把系統(tǒng)程序的工作線程全部停掉,禁止程序繼續(xù)運(yùn)行創(chuàng)建新的對(duì)象严就,然后通過分配多個(gè)線程(理論上4核CPU可以支持4個(gè)垃圾回收線程并行執(zhí)行)進(jìn)行垃圾回收工作总寻,提升性能,如下圖:
當(dāng)我們開發(fā)時(shí)想要系統(tǒng)指定使用ParNew垃圾回收器梢为,通過直接指定JVM參數(shù):“-XX:+UseParNewGC”即可渐行。默認(rèn)情況下,垃圾回收的線程數(shù)量跟我們的CPU的核數(shù)是一致的铸董,比如我們線上機(jī)器是8核CPU祟印,那么我們垃圾回收器對(duì)應(yīng)的線程數(shù)量也可以達(dá)到8個(gè)。當(dāng)然我們也可以手動(dòng)修改線程數(shù)量:“-XX:ParallelGCThreads”參數(shù)即可袒炉。(建議一般不要修改旁理,除非涉及到一些內(nèi)存優(yōu)化,后續(xù)我們?cè)俳Y(jié)合案例講解)
小結(jié)
本篇文章先給大家介紹下我們的兩個(gè)基礎(chǔ)核心垃圾收集器我磁,后續(xù)將繼續(xù)為大家介紹CMS垃圾收集器以及G1收集器的工作原理孽文。