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

面試時候總喜歡問的 JVM 要點在哪?

運維 數(shù)據(jù)庫運維 虛擬化
什么是新生代?主要是用來存放新生的對象。一般占據(jù)堆空間的1/3,由于頻繁創(chuàng)建對象,所以新生代會頻繁觸發(fā)MinorGC進行垃圾回收。

本文轉(zhuǎn)載自微信公眾號「Java極客技術(shù)」,作者鴨血粉絲 Tang。轉(zhuǎn)載本文請聯(lián)系Java極客技術(shù)公眾號。

面試的時候,很多面試官問 JVM 的時候,我們作為一個開發(fā)者,很多時候很難 Get 到面試官提問的要點,因為 JVM 確實太多了,從程序計數(shù)器開始,然后堆,然后棧,但是面試的時候卻總是回答不好這個問題,很多情況就是沒有系統(tǒng)的去看過所以回答面試題的時候,會出現(xiàn)語無倫次,這一塊內(nèi)容,那邊一塊內(nèi)容,總是回答不好,幾天阿粉就來分享給大家一個 JVM 的面試教程,對你有用的話,點贊關(guān)注和收藏一波。

你對 JVM 了解么?

首先,問這個問題的,一般都是問完了一些基礎(chǔ)了,這時候需要你自己從頭開始說 JVM 了,很多人實際上想到就是垃圾回收機制,確實,沒錯,但是,如果你直接就開始說是不是垃圾回收機制的時候,就已經(jīng)有點答非所問了。

為什么這么說,因為 JVM 的垃圾回收機制,都是發(fā)生在 堆內(nèi)存 的,但是,JVM 的劃分可不是只要堆內(nèi)存的,這時候回答應(yīng)該怎么回答?

** JVM 的內(nèi)部結(jié)構(gòu),最主要的內(nèi)部結(jié)構(gòu)是什么!**

JVM 分成了兩個部分

1.線程共享區(qū)域

2.線程私有區(qū)域

線程共享區(qū)域包含:堆(Heap)、方法區(qū)

線程私有區(qū)域包含:程序計數(shù)器、虛擬機棧(Stack)、本地方法棧

因為 JVM ,那可是不單單只有 堆(Heap) 的存在呀,其他的存在也是不可缺少的,為什么阿粉要這么說呢?

因為有些面試官會問 JVM 的類加載機制 你了解么?

如果你只是了解了垃圾回收機制的話,那你這個問題,是不是有點麻了,有點懵了,這不就芭比Q 了么?

那么 JVM 的類加載機制 是個什么呢?

回答:

首先通過類加載器(ClassLoader)會把 .class字節(jié)碼文件加載到內(nèi)存中——運行時數(shù)據(jù)區(qū)(Runtime Data Area),而字節(jié)碼文件只是 JVM 的一套指令集規(guī)范,并不能直接交給底層操作系統(tǒng)去執(zhí)行,因此需要特定的命令解析器執(zhí)行引擎(Execution Engine),將字節(jié)碼翻譯成底層系統(tǒng)指令,再交由 CPU 去執(zhí)行,而這個過程中需要調(diào)用其他語言的本地庫接口(Native Interface)來實現(xiàn)整個程序的功能。

跑偏了,我們繼續(xù)回答上一個問題,既然你說你了解了,你也回答了都有哪些內(nèi)部結(jié)構(gòu)了,是不是就該說說這些內(nèi)容是干啥的了,對,沒錯,就是這么回答。

  • 程序計數(shù)器:記錄線程執(zhí)行的位置,方便線程切換后再次執(zhí)行
  • 虛擬機棧(Stack):每個線程在創(chuàng)建時都會創(chuàng)建一個虛擬機棧,其內(nèi)部保存一個個的棧幀(Stack Frame),對應(yīng)著一次次的 Java 方法調(diào)用
  • 本地方法棧:是為了執(zhí)行native方法所服務(wù)的

說完這個,沒啥事別停頓,如果你停頓了,這時候面試官很有可能接著去問你棧的一些特性,你本身是想說垃圾回收機制的,總不能被帶跑偏吧,所以,繼續(xù)往下說。

  • 方法區(qū) :線程共享,存儲已經(jīng)被虛擬機加載的類信息、常量、靜態(tài)變量、即時編譯器編譯后的代碼等等

最后我們再說堆(Heap)

堆是 JVM 中最主要的區(qū)域了,因為堆(Heap)是 Java 虛擬機所管理的內(nèi)存中最大的一塊。

唯一目的就是儲存對象實例和數(shù)組(JDK7 已把字符串常量池和類靜態(tài)變量移動到 Java 堆),幾乎所有的對象實例都會存儲在堆中分配。

但是呢,隨著 JIT 編譯器發(fā)展,逃逸分析、棧上分配、標量替換等優(yōu)化技術(shù)導(dǎo)致并不是所有對象都會在堆上分配。

這時候,一般面試官都會開始提問了,就會讓你具體的說說堆內(nèi)存。

Java Heap 堆

Java 堆是垃圾收集器管理的主要區(qū)域。堆內(nèi)存分為新生代 (Young) 和老年代 (Old)

什么是新生代?

主要是用來存放新生的對象。一般占據(jù)堆空間的1/3,由于頻繁創(chuàng)建對象,所以新生代會頻繁觸發(fā)MinorGC進行垃圾回收。

什么是老年代?

老年代的對象比較穩(wěn)定,所以MajorGC不會頻繁執(zhí)行。

那么我們在分別來介紹一下 JVM 的新生代 和 老年代,就這兩個,足夠你和面試官聊上十幾分鐘的內(nèi)容了。

JVM 的新生代(垃圾回收機制)

新生代分為Eden區(qū)、ServivorFrom、ServivorTo三個區(qū)。

  • Eden區(qū)Java新對象的出生地(如果新創(chuàng)建的對象占用內(nèi)存很大則直接分配給老年代)。當Eden區(qū)內(nèi)存不夠的時候就會觸發(fā)一次MinorGc,對新生代區(qū)進行一次垃圾回收。
  • ServivorFrom區(qū)上一次GC的幸存者,作為這一次GC的被掃描者。當JVM無法為新建對象分配內(nèi)存空間的時候(Eden區(qū)滿的時候),JVM觸發(fā)MinorGc
  • ServivorTo區(qū)

保留了一次MinorGc過程中的幸存者。

那么新生代會使用什么樣子的垃圾回收機制呢?

我們每次new對象的時候都會先在新生代的Enden區(qū)放著也就是最開始 是這樣子的

然后在Enden用完的時候里面會出現(xiàn)待回收的

然后就來了把存活的對象復(fù)制放到Survior1(from)中,待回收的等待給他回收掉 就是這樣的

然后把Enden區(qū)清空回收掉

這樣的話 第一次GC就完成了,下面再往下走

當Enden充滿的時候就會再次GC

先是這個樣子的

然后會把 Enden和Survoir1中的內(nèi)容復(fù)制到Survior中,

然后就會把Enden和Survior進行回收

然后從Enden中過去的就相當于次數(shù)少的,而從Survior1中過去的就相當于移動了2次

這樣新生代的GC就執(zhí)行了2次了,

當Enden再次被使用完成的時候,就會從Survior2復(fù)制到Survior1中,

接下來是連圖

經(jīng)過回收之后Surior1就變了,1對象是從Enden直接復(fù)制過來的,2對象是Enden-->Survior2-->Survior1 ,3對象則是從Enden-->Surivior1-->Survior2-->Survior1 復(fù)制過來的,這樣一步一步的執(zhí)行下去的時候,就是新生代的GC。

這就是新生代采用的 GC ,如果你需要給面試官解釋,那么你就得熟練的記住這個圖,為什么這么說,因為只有你掌握了這個圖,那么你絕對會把這個復(fù)制算法給面試官講述的明明白白。

既然我們都知道了這個復(fù)制算法了,那么他到底有什么缺點呢?

  • 堆利用效率低 這是最明顯的,空間都被劈成兩半了,一次永遠只能用一半就得搬家
  • 遞歸調(diào)用 在對子對象進行復(fù)制時,使用了遞歸方法,可能導(dǎo)致棧溢出

但是我們也得吹一下復(fù)制算法的牛逼的地方呀。

吞吐量高所謂吞吐量就是搜索活動對象的時間比上搜索堆時間,越高說明你的有效搜索占比越高,不難看出,我們都是從根開始,搜索的全部是活動對象,并沒有浪費時間去搜索垃圾對象。這個優(yōu)勢在堆越大的場景下越明顯。

沒有碎片

在將活動對象復(fù)制到To空間時,他們都是緊挨著的,然后清空From時全部清空,完全沒有碎片的可能。

這也是新生代使用的垃圾回收的算法。

JVM 的老年代(垃圾回收機制)

老年代的垃圾回收機制,采用的則是和新生代不一樣的方式,有些人稱之為FullGC,而FullGC出現(xiàn)的原因則是:在新生代如果說存在的對象或者說新創(chuàng)建 出來的對象由于某些原因需要移動到老年代中,但是老年代中壓根就沒有這么大的內(nèi)存空間去容納這個對象, 那么就會引發(fā)一次FullGC,如果在執(zhí)行完FullGC之后,還是沒有辦法給這些對象分配內(nèi)存,那么涼了,該拋出異常了,異常類型就是OutOfMemoryError。

而FullGC使用的是和MinorGC不一樣的算法,它使用的是標記清除算法,聽名字,挺好理解的,來波圖示解析一波。深入了解JVM一書中的圖示是這個樣子的,

圖示是不是看著也挺明確,先標記,然后在刪除。

  • 標記(Mark)過程:找到所有的可以訪問的對象,做個指定的標記。
  • 清除(Swep)過程:遍歷堆內(nèi)存,把未標記的對象進行一個回收。

在了解了這個之后,我們還得說一個概念,那就是GC Root,Root我們可以理解成一個根節(jié)點就像這個樣子

上圖中的a,b,c,d,就是活著的對象,如果說存在這引用,比如說b引用的a,那么a他就是屬于活著的對象。當我們老年代內(nèi)存區(qū)中的有效的內(nèi)存空間不夠的時候,那么這時候整個世界都要安靜下來了(stop the world),這時候就要開始準備進行垃圾回收了。

  • 標記:遍歷所有的GC Roots,然后將所有GC Roots可達的對象標記為存活的對象。就是我們圖中所標記的a,b,c,d.?清除:清除的過程將遍歷堆中所有的對象,將沒有標記的對象全部清除掉。也就是說,如果內(nèi)存不夠,GC線程就會被觸發(fā)然后將程序暫停,隨后將依舊存活的對象標記一遍,最后再將堆中所有沒被標記的對象全部清除掉,接下來便讓程序繼續(xù)恢復(fù)運行。

流程圖就像這個樣子的 初始下的老年代中的對象狀態(tài)

這時候都是沒有被標記的狀態(tài),接下來內(nèi)存不夠,GC線程停止,開始進行標記了

按照根節(jié)點開始遍歷 標記的abcdeh都是存活的對象,接下來開始標記。

接下來就是清除數(shù)據(jù)了

清楚完成之后還有就是把標記去除掉,可以下次進行標記清除的時候繼續(xù)清除

其實這個阿粉的老讀者肯定看過,因為很早之前阿粉就畫出過這個圖。

這樣標記清除就執(zhí)行完畢了。

這時候不吹不黑,肯定會有優(yōu)缺點,不然為啥不采用其他的方法呢?畢竟 JVM 肯定是會選擇最適合自己的方式來進行 GC 的。

缺點清除后的堆內(nèi)存由于空間不連續(xù),即內(nèi)存碎片化,若下一次需要分配對象的內(nèi)存大于碎片空間,這樣會提前觸發(fā)GC,當提前觸發(fā)的GC回收后,空間還是不足就會出現(xiàn)OOM等錯誤。

時間問題:由于分為兩個過程(標記、清除),當堆內(nèi)可回收對象較多時,該算法需要進行大量的標記與清除,這里就產(chǎn)生一個問題,隨著可回收對象的的增多,標記和清除的效率就會下降;再者由于空間不連續(xù)導(dǎo)致每次再次分配都要遍歷空閑列表。

有點

實現(xiàn)簡單,與保守式GC算法兼容 這阿粉真的說不上他其他的優(yōu)點了,除了能夠解決引用計數(shù)算法帶來的不能清除循環(huán)引用的問題外,阿粉實在不知道了。

關(guān)于 JVM 的知識要點,你學(xué)會了么?

 

責(zé)任編輯:武曉燕 來源: Java極客技術(shù)
相關(guān)推薦

2019-12-23 15:17:21

JVM結(jié)構(gòu)

2021-12-25 22:31:10

MarkWord面試synchronize

2021-11-08 09:18:01

CAS面試場景

2021-12-16 18:38:13

面試Synchronize

2021-12-02 18:20:25

算法垃圾回收

2023-06-07 08:08:43

JVM內(nèi)存模型

2021-12-06 11:03:57

JVM性能調(diào)優(yōu)

2024-03-25 11:03:38

Vue修飾符lazy

2022-01-05 08:56:20

Vue修飾符面試

2010-08-10 16:21:48

面試薪資

2024-03-13 13:39:21

2016-03-02 15:13:54

面試開發(fā)者問題

2012-08-20 14:09:29

面試

2015-07-03 11:19:43

火車WiFi

2023-09-12 11:38:18

2024-03-28 08:43:42

webpack代碼true?

2021-07-14 07:21:57

JVM運行數(shù)據(jù)

2019-09-12 10:14:36

技術(shù)研發(fā)面試

2010-10-25 10:48:22

面試

2010-08-09 16:30:53

面試
點贊
收藏

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