亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

高頻率JVM面試問題整理(大廠面試經(jīng))

  發(fā)布時間:2020-03-23 16:24:33   作者:架構(gòu)文摘   我要評論
這篇文章主要介紹了高頻率JVM面試問題整理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

JVM(Java虛擬機(jī))簡單來說就是運(yùn)行Java代碼的解釋器,作為螺絲釘程序員JVM其實(shí)了解下就差不多啦,不懂JVM內(nèi)部細(xì)節(jié)照樣能寫出優(yōu)質(zhì)的代碼!但是一到造火箭、飛機(jī)的場景(面試)不懂JVM的你,會被面試官虐的體無完膚,本期內(nèi)容列舉常見的JVM面試題:

  • 說一JVM的內(nèi)存模型是什么樣子的?
  • 什么時候?qū)ο罂梢员皇栈兀?/li>
  • 常見的垃圾回收器算法有哪些,各有什么優(yōu)劣?
  • 什么時候?qū)ο髸M(jìn)入老年代?
  • 什么是空間分配擔(dān)保策略?
  • 如何優(yōu)化減少Full GC?

面對這一大波JVM面試題,你真的Hold住嗎?

JVM的內(nèi)存結(jié)構(gòu)是什么樣子的?

JVM內(nèi)存結(jié)構(gòu)可以大致可劃分為線程私有區(qū)域和共享區(qū)域,線程私有區(qū)域由虛擬機(jī)棧、本地方法棧、程序計數(shù)器組成,而共享區(qū)域由堆、元數(shù)據(jù)空間(方法區(qū))組成。

再有人問你JVM的內(nèi)存結(jié)構(gòu)就回想下上面的圖,但是知道JVM的內(nèi)存模型的樣子還是不行的,還要知道他們分別干什么的。

虛擬機(jī)棧/本地方法棧

當(dāng)你碰到過StackOverflowException這個異常的時候,有沒有思考下為什么會出現(xiàn)這樣的異常呢?答案就在虛擬機(jī)棧中,JVM會為每個方法生成棧幀然后將棧幀壓入虛擬機(jī)棧中。

舉個粟子:假設(shè)JVM參數(shù)-Xss設(shè)置為1m,如果某個方法里面創(chuàng)建一個128kb的數(shù)組,那這個方法在同一個線程中只能遞歸4次,再遞歸第五次的時候就會報StackOverflowException異常,因為虛擬機(jī)棧的大小只有1m,每次遞歸都需要為方法在虛擬機(jī)棧中分配128kb的空間,很顯示到第五次的時候就空間不足了。

程序計數(shù)器

程序計數(shù)器是一個記錄著當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器。JVM的多線程是通過CPU時間片輪轉(zhuǎn)(即線程輪流切換并分配處理器執(zhí)行時間)算法來實(shí)現(xiàn)的。也就是說,某個線程在執(zhí)行過程中可能會因為時間片耗盡而被掛起,而另一個線程獲取到時間片開始執(zhí)行。

簡單的說程序計數(shù)器的主要功能就是記錄著當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器。

方法區(qū)(元數(shù)據(jù)區(qū))

方法區(qū)存儲了類的元數(shù)據(jù)信息、靜態(tài)變量、常量等數(shù)據(jù)。

堆(heap)

平常大家使用new關(guān)鍵字創(chuàng)建的對象都會進(jìn)入堆中,堆也是GC重點(diǎn)照顧的區(qū)域,堆會被劃分為:新生代、老年代,而新生代還會被進(jìn)一步劃分為Eden區(qū)和Survivor區(qū):

新生代中的Eden區(qū)和Survivor區(qū),是根據(jù)JVM回收算法來的,只是現(xiàn)在大部分都是使用的分代回收算法,所以在介紹堆的時候會直接將新生代歸納為Eden區(qū)和Survivor區(qū)。

小結(jié)

JVM內(nèi)存模型小結(jié):

  • JVM內(nèi)存模型劃分為線程私有區(qū)域和共享區(qū)域
  • 虛擬機(jī)棧/本地方法棧負(fù)責(zé)存放線程執(zhí)行方法棧幀
  • 程序計數(shù)器用于記錄線程執(zhí)行指令的位置
  • 方法區(qū)(元數(shù)據(jù)區(qū))存儲類的元數(shù)據(jù)信息、靜態(tài)變量、常量等數(shù)據(jù)
  • 堆(heap)使用new關(guān)鍵字創(chuàng)建的對象都會進(jìn)入堆中,堆被劃分為新生代和老年代

什么時候?qū)ο罂梢员皇栈兀?/strong>

JVM判斷對象回收有兩種方式:引用記數(shù)、GC Roots,引用記數(shù)比較簡單,JVM為每個對象維護(hù)一個引用計數(shù),假設(shè)A對象引用計數(shù)為零說明沒有任務(wù)對象引用A對象,那A對象就可以被回收了,但是引用計數(shù)有個缺點(diǎn)就是無法解決循環(huán)引用的問題。

GC Roots通過一系列的名為GC Roots的對象作為起始點(diǎn),從這些節(jié)點(diǎn)開始向下搜索,搜索過的路徑稱為引用鏈,當(dāng)一個對象到GC Roots沒有任何引用鏈相連時,則證明對象是不可用的。

在Java中,可以作為GC Roots的對象包括下面幾種:

  • 虛擬機(jī)棧中引用的對象;
  • 方法區(qū)中類靜態(tài)屬性引用的對象;
  • 方法區(qū)中的常量引用的對象;
  • 本地方法棧中JNI(即一般說的Native方法)的引用的對象;

小結(jié)

總的來說就是當(dāng)一個對象通過GC Roots搜索不到時,說明對象可以被回收了,但什么時候回收還要看GC的心情!

常見的垃圾回收器算法有哪些,各有什么優(yōu)劣?

標(biāo)記清除

這種算法分兩分:標(biāo)記、清除兩個階段,
標(biāo)記階段是從根集合(GC Root)開始掃描,每到達(dá)一個對象就會標(biāo)記該對象為存活狀態(tài),清除階段在掃描完成之后將沒有標(biāo)記的對象給清除掉。

用一張圖說明:

這個算法有個缺陷就是會產(chǎn)生內(nèi)存碎片,如上圖B被清除掉后會留下一塊內(nèi)存區(qū)域,如果后面需要分配大的對象就會導(dǎo)致沒有連續(xù)的內(nèi)存可供使用。

標(biāo)記整理

標(biāo)記整理就沒有內(nèi)存碎片的問題了,也是從根集合(GC Root)開始掃描進(jìn)行標(biāo)記然后清除無用的對象,清除完成后它會整理內(nèi)存。

這樣內(nèi)存就是連續(xù)的了,但是產(chǎn)生的另外一個問題是:每次都得移動對象,因此成本很高。

復(fù)制算法

復(fù)制算法會將JVM推分成二等分,如果堆設(shè)置的是1g,那使用復(fù)制算法的時候堆就會有被劃分為兩塊區(qū)域各512m。給對象分配內(nèi)存的時候總是使用其中的一塊來分配,分配滿了以后,GC就會進(jìn)行標(biāo)記,然后將存活的對象移動到另外一塊空白的區(qū)域,然后清除掉所有沒有存活的對象,這樣重復(fù)的處理,始終就會有一塊空白的區(qū)域沒有被合理的利用到。

兩塊區(qū)域交替使用,最大問題就是會導(dǎo)致空間的浪費(fèi),現(xiàn)在堆內(nèi)存的使用率只有50%。

小結(jié)

JVM回收算法小結(jié):

  • 標(biāo)記清除速度快,但是會產(chǎn)生內(nèi)存碎片;
  • 標(biāo)記整理解決了標(biāo)記清除內(nèi)存碎片的問題,但是每次都得移動對象,因此成本很高;
  • 復(fù)制算法沒有內(nèi)存碎片也不需要移動對象,但是導(dǎo)致空間的浪費(fèi);

什么時候?qū)ο髸M(jìn)入老年代?

新創(chuàng)建出來的對象一開始都會停留在新生代中,但隨著JVM的運(yùn)行,有些存活的長的對象會慢慢的移動到老年代中。

根據(jù)對象年齡

JVM會給對象增加一個年齡(age)的計數(shù)器,對象每“熬過”一次GC,年齡就要+1,待對象到達(dá)設(shè)置的閾值(默認(rèn)為15歲)就會被移移動到老年代,可通過-XX:MaxTenuringThreshold調(diào)整這個閾值。

一次Minor GC后,對象年齡就會+1,達(dá)到閾值的對象就移動到老年代,其他存活下來的對象會繼續(xù)保留在新生代中。

動態(tài)年齡判斷

根據(jù)對象年齡有另外一個策略也會讓對象進(jìn)入老年代,不用等待15次GC之后進(jìn)入老年代,他的大致規(guī)則就是,假如當(dāng)前放對象的Survivor,一批對象的總大小大于這塊Survivor內(nèi)存的50%,那么大于這批對象年齡的對象,就可以直接進(jìn)入老年代了。

如圖上的A、B、D、E這四個對象,假如Survivor 2是100m,如果A + B + D的內(nèi)存大小超過50m,現(xiàn)在D的年齡是10,那E都會被移動到老年代。實(shí)際上這個計算邏輯是這樣的:年齡1 + 年齡2 + 年齡n的多個對象總和超過Survivor區(qū)的50%,那就會把年齡n以上的對象都放入老年代。

大對象直接進(jìn)入老年代

如果設(shè)置了-XX:PretenureSizeThreshold這個參數(shù),那么如果你要創(chuàng)建的對象大于這個參數(shù)的值,比如分配一個超大的字節(jié)數(shù)組,此時就直接把這個大對象放入到老年代,不會經(jīng)過新生代。

這么做就可以避免大對象在新生代,屢次躲過GC,還得把他們來復(fù)制來復(fù)制去的,最后才進(jìn)入老年代,這么大的對象來回復(fù)制,是很耗費(fèi)時間的。

什么是空間分配擔(dān)保策略?

JVM在發(fā)生Minor GC之前,虛擬機(jī)會檢查老年代最大可用的連續(xù)空間是否大于新生代所有對象的總空間,如果大于,則此次Minor GC是安全的如果小于,則虛擬機(jī)會查看HandlePromotionFailure設(shè)置項的值是否允許擔(dān)保失敗。如果HandlePromotionFailure=true,那么會繼續(xù)檢查老年代最大可用連續(xù)空間是否大于歷次晉升到老年代的對象的平均大小,如果大于則嘗試進(jìn)行一次Minor GC,但這次Minor GC依然是有風(fēng)險的;如果小于或者HandlePromotionFailure=false,則改為進(jìn)行一次Full GC。

如何優(yōu)化減少Full GC?

將前面的一些問題總結(jié)下來,然后應(yīng)用到線上,那JVM應(yīng)該如何優(yōu)化減少Full GC呢?以標(biāo)準(zhǔn)的4核8G機(jī)器為例說明,首先系統(tǒng)預(yù)留4G,其他4G按如下規(guī)則分配 :

  • 堆內(nèi)存:3g
  • 新生代:1.5g
  • 新生代Eden區(qū):1228m
  • 新生代Survivor區(qū):153m
  • 方法區(qū):256m
  • 虛擬機(jī)棧:1m/thread

設(shè)置參數(shù)如下:

-Xms3072m
-Xmx3072m
-Xmn1536m
-Xss=1m
-XX:PermSize=256m
-XX:MaxPermSize=256m
-XX:HandlePromotionFailure
-XX:SurvivorRatio=8

估算系統(tǒng)每秒占用內(nèi)存數(shù)量

在優(yōu)化JVM之前,要先估算要系統(tǒng)每秒占用的內(nèi)存數(shù)量,如有個日活百萬的商場系統(tǒng),每日下單量在20w左右,按照一天8個小時算,那訂單服務(wù)的每秒大概會有500個請求,然后粗略的估算下每個請求占用多少內(nèi)存,計算出每秒要花費(fèi)多少內(nèi)存。

假設(shè)是每秒500個請求,每個請求需要分配100k的空間,那1秒需要分配大約50m的內(nèi)存。

計算下多長時間觸發(fā)一次Minor GC

按照之前的估算1秒需要分配大約50m的內(nèi)存的話,Eden區(qū)的空間是1228m那平均每25秒就要執(zhí)行一次Minor GC。

檢查下Survivor區(qū)是否足夠

按照上面的模型,每25秒就要執(zhí)行一次Minor GC,GC執(zhí)行期間并不能回收掉所有的新生代中的對象,那每秒50m那每次GC執(zhí)行期間還會剩下大約100m無法回收的對象會進(jìn)入Survivor區(qū),但是別忘記JVM有動態(tài)年齡判斷機(jī)制,這樣設(shè)置下來Survivor的空間明顯小了一點(diǎn),所以將新生代設(shè)置2048m,才能避免觸發(fā)動態(tài)年齡判斷:

-Xms3072m
-Xmx3072m
-Xmn2048m
...

大對象直接進(jìn)入老年代

大對象一般是長期存活和使用的對象,一般來說設(shè)置1M的對象直接進(jìn)入老年代,這樣避免大對象一直處于新生代中來回復(fù)制,所以加上PretenureSizeThreshold=1m參數(shù)。

...
-XX:PretenureSizeThreshold=1m
...

合理設(shè)置對象年齡閾值

Minor GC后默認(rèn)躲過15次垃圾回收后自動升入老年代,按照我們的評估25秒觸發(fā)一次Minor GC,如果按照MaxTenuringThreshold參數(shù)的默認(rèn)值,躲過15次GC后,應(yīng)該是6分鐘之后的事了,結(jié)合當(dāng)前業(yè)務(wù)場景這里可以降低一點(diǎn),讓那些本應(yīng)該進(jìn)入老年代的對象,盡快的進(jìn)入老年代,避免復(fù)制成本和浪費(fèi)新生代空間,從而導(dǎo)致新生代Survivor空間不足,引發(fā)Full GC。

...
-XX:MaxTenuringThreshold=6
...

到此這篇關(guān)于高頻率JVM面試問題整理(大廠面試經(jīng))的文章就介紹到這了,更多相關(guān)JVM面試內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持腳本之家!

相關(guān)文章

  • 2020年JVM高頻率面試題整理

    這篇文章主要介紹了2020年JVM高頻率面試題整理,真是小編下了血本給大家整理出來的,值得大家收藏,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-03-09
  • JVM面試題小結(jié)(2020最新版)

    這篇文章主要介紹了JVM面試題小結(jié)(2020最新版),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2020-02-21
  • 2019年JVM面試都問了什么?(附答案解析)

    這篇文章主要介紹了2019年JVM面試都問了什么?(附答案解析),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-12-04
  • 大廠面試經(jīng):說一下你們線上JVM是如何優(yōu)化的

    JVM(Java虛擬機(jī))簡單來說就是運(yùn)行Java代碼的解釋器,作為螺絲釘程序員JVM其實(shí)了解下就差不多啦,不懂JVM內(nèi)部細(xì)節(jié)照樣能寫出優(yōu)質(zhì)的代碼!這篇文章主要介紹了大廠面試經(jīng):
    2019-11-12
  • Java研發(fā)面試99題(含答案):JVM+Spring+MySQL+線程池+鎖

    這篇文章主要介紹了Java研發(fā)面試99題,主要包括了JVM,Spring,MySQL,線程池,鎖等,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-07-16
  • 講一講JVM的組成(Java經(jīng)典面試題)

    JVM(Java 虛擬機(jī))算是面試必問的問題的了,而但凡問 JVM 一定會問的第一個問題就是:講一講 JVM 的組成?那本文就注重講一下 JVM 的組成,感興趣的可以了解一下
    2019-04-10

最新評論