自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

vivo 校招:說(shuō)一說(shuō) JVM 垃圾回收算法有哪些?分別用在哪些垃圾收

開(kāi)發(fā) 前端
下面就分享一位校招同學(xué)在 vivo Java 后端崗位面試中就有問(wèn)到 JVM 垃圾回收算法以及這些算法分別用在哪些垃圾收集器?

大家好,我是碼哥,可以叫我靚仔。

最近 vivo 校招薪資開(kāi)獎(jiǎng)了,想必互聯(lián)網(wǎng)公司給的不算多,有的同學(xué)達(dá)到 vivo offer 后直接拒了。

vivo 的面試難度如何?

下面就分享一位校招同學(xué)在 vivo Java 后端崗位面試中就有問(wèn)到 JVM 垃圾回收算法以及這些算法分別用在哪些垃圾收集器?

圖片

vivo 一面

JVM 垃圾回收時(shí)自動(dòng)管理內(nèi)存的一種機(jī)制,用于釋放不再使用的對(duì)象所占用的內(nèi)存空間。
一般是通過(guò)兩個(gè)步驟實(shí)現(xiàn):

  1. 標(biāo)記階段:識(shí)別可回收的垃圾對(duì)象。
  2. 清除階段:回收標(biāo)記為垃圾的對(duì)象所占的內(nèi)存。

下面我們先來(lái)看下垃圾的標(biāo)記是如何實(shí)現(xiàn)的。

垃圾標(biāo)記方式

通常,標(biāo)記垃圾有兩種方式:引用計(jì)數(shù)和可達(dá)性分析。

引用計(jì)數(shù)

通過(guò)維護(hù)每個(gè)對(duì)象的引用計(jì)數(shù)來(lái)判斷對(duì)象是否可以被回收。當(dāng)有一個(gè)指針引用它,那么引用計(jì)數(shù)+1,當(dāng)引用計(jì)數(shù)為 0 時(shí),表示沒(méi)有被對(duì)象引用,可以被回收。

但是引用計(jì)數(shù)會(huì)存在一個(gè)問(wèn)題,就是對(duì)象互相引用會(huì)導(dǎo)致-循環(huán)引用,形成一個(gè)環(huán)狀,這樣在這個(gè)循環(huán)引用的環(huán)內(nèi)所有對(duì)象的引用次數(shù)至少都為 1,那么這些對(duì)象永遠(yuǎn)無(wú)法被回收了。

可達(dá)性分析算法

Java 采用的也是這一種,可達(dá)性分析算法表示從 GC Roots 為起點(diǎn),開(kāi)始查找存活對(duì)象,在查找過(guò)的路徑稱為引用鏈,所有能訪問(wèn)到對(duì)象標(biāo)記為“可達(dá)”,無(wú)法訪問(wèn)到的對(duì)象就是不可達(dá),也就是可以被回收的垃圾。

哪些可以作為 GC ROOTS 對(duì)象呢?

  1. 虛擬機(jī)棧的引用:方法中的局部變量。
  2. 方法區(qū)中的類靜態(tài)屬性、常量引用的對(duì)象。
  3. JNI(Java Native Interface)引用:本地方法持有的對(duì)象引用。
  4. 正在被線程引用的對(duì)象。

那么在找到垃圾后,如何進(jìn)行回收垃圾呢?

垃圾回收算法

標(biāo)記-清除算法

主要分為“標(biāo)記”和“清除”兩個(gè)階段,標(biāo)記存在引用的對(duì)象,回收未被標(biāo)記的對(duì)象空間。

存在問(wèn)題:

  • 效率不高,因?yàn)樾枰獦?biāo)記的對(duì)象太多。
  • 存在大量不連續(xù)的空間碎片

復(fù)制算法

主要是將內(nèi)存分為大小相同的兩部分,每次只使用其中一個(gè),當(dāng)其中一個(gè)的內(nèi)存使用完時(shí),把存活的對(duì)象復(fù)制到另一邊去,然后把剩下的空間清理掉。

這樣可以提高一定效率,但缺點(diǎn)是內(nèi)存空間使用不高。

標(biāo)記-整理算法

標(biāo)記過(guò)程和“標(biāo)記-清除”算法一致,但在回收階段,它是讓所有存活的對(duì)象移動(dòng)至一端,然后清理掉邊界以外的對(duì)象。

分代收集算法

分代收集算法主要是將 Java 堆分為年輕代和老年代兩個(gè)區(qū)域。

  • 年輕代:年輕代的絕大多數(shù)對(duì)象都是朝生夕亡的,每次回收只需要關(guān)注如何保存少量存活的對(duì)象,而不是標(biāo)記大量即將回收的對(duì)象。
  • 老年代:老年代的絕大多數(shù)對(duì)象是存活時(shí)間較長(zhǎng)的對(duì)象。

垃圾收集器

垃圾收集器是 JVM 中對(duì)垃圾回收算法的具體實(shí)現(xiàn)。

Serial 收集器

Serial(串行)收集器是最基本的垃圾收集器了,它是一個(gè)單線程收集器,進(jìn)行垃圾回收時(shí),只會(huì)用一個(gè)線程去完成垃圾回收工作,同時(shí)會(huì)讓其他所有的工作線程停止(Stop The World),等待它執(zhí)行完成。

Parallel Scavengel 收集器

Parallel Scavengel 收集器其實(shí)就是 Serial 的多線程版本,使用多線程進(jìn)行垃圾回收,而它的系統(tǒng)吞吐量自然也是比 Serial 的要高。

ParNew 收集器

ParNew 收集器和 Parallel Scavengel 收集器十分類似,通常會(huì)和 CMS 結(jié)合使用,新生代采用它完成垃圾回收。

CMS 收集器

CMS,Concurrent Mark Sweep,是一款追求以最短回收時(shí)間為目標(biāo)的垃圾收集器,注重提升用戶體驗(yàn),它是第一次實(shí)現(xiàn)了同時(shí)讓垃圾回收線程和用戶線程一起工作。

CMS 是基于“標(biāo)記-清除”算法實(shí)現(xiàn)的,它的運(yùn)作過(guò)程有以下幾個(gè)步驟:

  • 初始標(biāo)記:暫停所有的線程,記錄下 GC Roots 直接引用到的對(duì)象,這個(gè)過(guò)程耗時(shí)非常短。
  • 并發(fā)標(biāo)記:這個(gè)過(guò)程是和用戶線程并發(fā)運(yùn)行的,就是從 GC Roots 直接引用對(duì)象開(kāi)始遍歷,雖然耗時(shí)較長(zhǎng),但也不影響用戶程序,但是會(huì)存在一個(gè)問(wèn)題就是,因?yàn)橛脩艟€程是不暫停的(Stop The World),可能有些已經(jīng)標(biāo)記過(guò)的對(duì)象狀態(tài)會(huì)發(fā)生改變。
  • 重新標(biāo)記:這個(gè)過(guò)程就是為了修正上一階段因?yàn)橛脩艟€程導(dǎo)致的已經(jīng)標(biāo)記過(guò)對(duì)象的狀態(tài)發(fā)生改變的記錄,主要處理多標(biāo)、漏標(biāo)問(wèn)題。這個(gè)過(guò)程會(huì)比初始標(biāo)記階段的耗時(shí)長(zhǎng),但也遠(yuǎn)低于并發(fā)標(biāo)記階段。
  • 并發(fā)清理:和用戶線程并發(fā)運(yùn)行,GC 線程對(duì)為標(biāo)記的區(qū)域清理。
  • 并發(fā)重置:重置本次 GC 的標(biāo)記數(shù)據(jù)。

從上面過(guò)程就可看出,CMS 的主要特點(diǎn)是:并發(fā)收集,延遲低。但也存在幾個(gè)缺點(diǎn):

  • 占用 CPU 資源
  • 無(wú)法處理浮動(dòng)垃圾,即并發(fā)清理階段中產(chǎn)生新的垃圾,只能等到下一次 GC 再清理。
  • 因?yàn)樗褂玫氖恰皹?biāo)記-清除”算法,這個(gè)會(huì)產(chǎn)生大量?jī)?nèi)存空間碎片。
  • 某些情況下,會(huì)導(dǎo)致 CMS 退化成 Serial Old 垃圾收集器,比如上一次老年代存在大量垃圾未收集完成,這時(shí)垃圾回收又被觸發(fā)。

CMS 有哪些常用的參數(shù)呢?

-XX:+UseConcMarkSweepGC,啟用 CMS 收集器,注意 JDK8 默認(rèn)使用的是 Parallel GC,JDK9 以后使用 G1 GC。

-XX:ConcGCThreads,CMS 并發(fā)過(guò)程運(yùn)行的線程數(shù)。

-XX:+UseCMSCompactAtFullCollection,F(xiàn)ullGC 完成后再做壓縮整理,針對(duì) CMS 容易產(chǎn)生內(nèi)存碎片做的優(yōu)化。

-XX:CMSFullGCsBeforeCompaction,配合上面使用,多少次 FullGC 完成后進(jìn)行壓縮,,默認(rèn)是 0,即每次都會(huì)壓縮。

-XX:CMSInitiatingOccupancyFraction,老年代使用達(dá)到的某個(gè)比例時(shí)會(huì)觸發(fā) FullGC,默認(rèn)是 92。

-XX:+CMSParallellnitialMarkEnabled,表示在初始標(biāo)記階段采用多線程執(zhí)行,減少 STW 時(shí)間。

-XX:+CMSParallelRemarkEnabled,表示在重新標(biāo)記階段采用多線程執(zhí)行,減少 STW 時(shí)間。

G1 收集器

G1 是一面向服務(wù)器的垃圾收集器,主要針對(duì)多處理器和大內(nèi)存的機(jī)器,在極高概率滿足 GC 停頓時(shí)間要求的同時(shí),具備高吞吐量特性。

G1 將 Java 堆劃分為多個(gè)大小相等的獨(dú)立區(qū)域(Region),JVM 最多可以有 2048 個(gè) Region。一般 Region 大小等于堆大小除以 2048,比如堆大小為 4096M,則 Region 大小為 2M。

G1 保留了年輕代和老年代的概念,但不再是物理隔閡了,它們都是(可以不連續(xù))Region 的集合。默認(rèn)年輕代對(duì)堆內(nèi)存的占比是 5%,如果堆大小為 4096M,那么年輕代占據(jù) 200MB 左右的內(nèi)存,對(duì)應(yīng)大概是 100 個(gè) Region。

G1 回收步驟:

  • 初始標(biāo)記:暫停所有的線程,記錄下 GC Roots 直接引用到的對(duì)象,這個(gè)過(guò)程耗時(shí)非常短。
  • 并發(fā)標(biāo)記:同 CMS。
  • 最終標(biāo)記:和 CMS 的重新標(biāo)記一樣。
  • 篩選回收:首先對(duì)各 Region 的回收價(jià)值和成本進(jìn)行計(jì)算,根據(jù)用戶設(shè)定的 GC 停頓時(shí)間(-XX:MaxGCPauseMillis 參數(shù))來(lái)制定回收計(jì)劃,比如此時(shí)又 1000 個(gè) Region 需要回收,但是用戶設(shè)置的停頓時(shí)間是 200ms,那么通過(guò)之前回收成本計(jì)算,只會(huì)回收其中部分 Region 比如 600 個(gè),所以時(shí)間是用戶可控的?;厥账惴ㄖ饕玫膹?fù)制算法,把一個(gè) Region 存活的對(duì)象復(fù)制到另外一個(gè) Region 中,所以不會(huì)像 CMS 那樣存在內(nèi)存碎片。
責(zé)任編輯:姜華 來(lái)源: 碼哥跳動(dòng)
相關(guān)推薦

2022-01-20 10:34:49

JVM垃圾回收算法

2017-08-04 10:53:30

回收算法JVM垃圾回收器

2023-12-07 12:21:04

GCJVM垃圾

2022-03-21 11:33:11

JVM垃圾回收器垃圾回收算法

2023-12-29 10:28:24

SPIJava靈活性

2021-11-05 15:23:20

JVM回收算法

2009-12-25 16:15:31

JVM垃圾回收算法

2024-12-03 09:01:33

2010-09-26 13:29:46

JVM垃圾回收

2021-03-11 07:26:52

垃圾回收器單線程

2023-08-08 10:29:55

JVM優(yōu)化垃圾回收

2012-01-09 16:53:36

JavaJVM

2021-02-04 10:43:52

開(kāi)發(fā)技能代碼

2022-06-10 07:13:29

JVM垃圾回收

2010-09-25 15:33:19

JVM垃圾回收

2009-12-30 10:14:29

JVM垃圾回收

2022-06-22 09:54:45

JVM垃圾回收Java

2021-06-27 21:10:12

Linux 進(jìn)程控制

2010-12-13 11:14:04

Java垃圾回收算法

2024-02-27 00:10:06

語(yǔ)言Javascript
點(diǎn)贊
收藏

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