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

【死磕JVM】這可能是最全的JVM面試題了

開(kāi)發(fā) 前端
本篇帶給大家一篇全網(wǎng)最全的JVM面試題,希望對(duì)你有所幫助!

[[404599]]

1. 描述一下jvm內(nèi)存模型


2.堆內(nèi)存劃分的空間

垃圾回收算法: 標(biāo)記清除、復(fù)制(多為新生代垃圾回收使用)、標(biāo)記整理

3.如何解決線上gc頻繁的問(wèn)題?

  1. 查看監(jiān)控,以了解出現(xiàn)問(wèn)題的時(shí)間點(diǎn)以及當(dāng)前FGC的頻率(可對(duì)比正常情況看頻率是否正常)
  2. 了解該時(shí)間點(diǎn)之前有沒(méi)有程序上線、基礎(chǔ)組件升級(jí)等情況。
  3. 了解JVM的參數(shù)設(shè)置,包括:堆空間各個(gè)區(qū)域的大小設(shè)置,新生代和老年代分別采用了哪些垃 圾收集器,然后分析JVM參數(shù)設(shè)置是否合理。
  4. 再對(duì)步驟1中列出的可能原因做排除法,其中元空間被打滿(mǎn)、內(nèi)存泄漏、代碼顯式調(diào)用gc方法 比較容易排查。
  5. 針對(duì)大對(duì)象或者長(zhǎng)生命周期對(duì)象導(dǎo)致的FGC,可通過(guò) jmap -histo 命令并結(jié)合dump堆內(nèi)存文件作進(jìn)一步分析,需要先定位到可疑對(duì)象。
  6. 通過(guò)可疑對(duì)象定位到具體代碼再次分析,這時(shí)候要結(jié)合GC原理和JVM參數(shù)設(shè)置,弄清楚可疑 對(duì)象是否滿(mǎn)足了進(jìn)入到老年代的條件才能下結(jié)論。

4.描述一下class初始化過(guò)程?

一個(gè)類(lèi)初始化就是執(zhí)行clinit()方法,過(guò)程如下:

  • 父類(lèi)初始化
  • static變量初始化/static塊(按照文本順序執(zhí)行)

Java Language Specification中,類(lèi)初始化詳細(xì)過(guò)程如下(最重要的是類(lèi)初始化是線程安全的):

  1. 每個(gè)類(lèi)都有一個(gè)初始化鎖LC,進(jìn)程獲取LC(如果沒(méi)有獲取到,就一直等待)
  2. 如果C正在被其他線程初始化,釋放LC并等待C初始化完成
  3. 如果C正在被本線程初始化,即遞歸初始化,釋放LC
  4. 如果C已經(jīng)被初始化了,釋放LC
  5. 如果C處于erroneous狀態(tài),釋放LC并拋出異常NoClassDefFoundError
  6. 否則,將C標(biāo)記為正在被本線程初始化,釋放LC;然后, 初始化那些final且為基礎(chǔ)類(lèi)型的類(lèi)成員變量
  7. 初始化C的父類(lèi)SC和各個(gè)接口SI_n(按照implements子句中的順序來(lái)) ;如果SC或SIn初始化過(guò)程中拋出異常,則獲取LC,將C標(biāo)記為erroneous,并通知所有線程,然后釋放LC,然后 再拋出同樣的異常。
  8. 從classloader處獲取assertion是否被打開(kāi)
  9. 接下來(lái), 按照文本順序執(zhí)行類(lèi)變量初始化和靜態(tài)代碼塊,或接口的字段初始化,把它們當(dāng)作是一個(gè)個(gè)單獨(dú)的代碼塊。
  10. 如果執(zhí)行正常,獲取LC,標(biāo)記C為已初始化,并通知所有線程,然后釋放LC
  11. 否則,如果拋出了異常E。若E不是Error,則以E為參數(shù)創(chuàng)建新的異常ExceptionInInitializerError作為E。如果因?yàn)镺utOfMemoryError導(dǎo)致無(wú)法創(chuàng)建ExceptionInInitializerError,則將OutOfMemoryError作為E。
  12. 獲取LC,將C標(biāo)記為erroneous,通知所有等待的線程,釋放LC,并拋出異常E

5.簡(jiǎn)述一下內(nèi)存溢出的原因,如何排查線上問(wèn)題?

內(nèi)存溢出的原因

  • java.lang.OutOfMemoryError: ......java heap space. 堆棧溢出,代碼問(wèn)題的可能性極大
  • java.lang.OutOfMemoryError: GC over head limit exceeded 系統(tǒng)處于高頻的GC狀態(tài),而且回收的效果依然不佳的情況,就會(huì)開(kāi)始報(bào)這個(gè)錯(cuò)誤,這種情況一般是產(chǎn)生了很多不可以被釋放 的對(duì)象,有可能是引用使用不當(dāng)導(dǎo)致,或申請(qǐng)大對(duì)象導(dǎo)致,但是java heap space的內(nèi)存溢出有可能提前不會(huì)報(bào)這個(gè)錯(cuò)誤,也就是可能內(nèi)存就直接不夠?qū)е?,而不是高頻GC.
  • java.lang.OutOfMemoryError: PermGen space jdk1.7之前才會(huì)出現(xiàn)的問(wèn)題 ,原因是系統(tǒng)的代碼非常多或引用的第三方包非常多、或代碼中使用了大量的常量、或通過(guò)intern注入常量、 或者通過(guò)動(dòng)態(tài)代碼加載等方法,導(dǎo)致常量池的膨脹
  • java.lang.OutOfMemoryError: Direct buffer memory 直接內(nèi)存不足,因?yàn)閖vm垃圾回收不會(huì)回收掉直接內(nèi)存這部分的內(nèi)存,所以可能原因是直接或間接使用了ByteBuffer中的allocateDirect方法的時(shí)候,而沒(méi)有做clear
  • java.lang.StackOverflowError - Xss設(shè)置的太小了
  • java.lang.OutOfMemoryError: unable to create new native thread 堆外內(nèi)存不足,無(wú)法為線程分配內(nèi)存區(qū)域
  • java.lang.OutOfMemoryError: request {} byte for {}out of swap 地址空間不夠

6.jvm有哪些垃圾回收器,實(shí)際中如何選擇?

圖中展示了7種作用于不同分代的收集器,如果兩個(gè)收集器之間存在連線,則說(shuō)明它們可以搭配使用。虛 擬機(jī)所處的區(qū)域則表示它是屬于新生代還是老年代收集器。

新生代收集器(全部的都是復(fù)制算法):Serial、ParNew、Parallel Scavenge

老年代收集器:CMS(標(biāo)記-清理)、Serial Old(標(biāo)記-整理)、Parallel Old(標(biāo)記整理) 整堆收集器:G1(一個(gè)Region中是標(biāo)記-清除算法,2個(gè)Region之間是復(fù)制算法)

同時(shí),先解釋幾個(gè)名詞:

  1. 并行(Parallel):多個(gè)垃圾收集線程并行工作,此時(shí)用戶(hù)線程處于等待狀態(tài)
  2. 并發(fā)(Concurrent):用戶(hù)線程和垃圾收集線程同時(shí)執(zhí)行
  3. 吞吐量:運(yùn)行用戶(hù)代碼時(shí)間/(運(yùn)行用戶(hù)代碼時(shí)間+垃圾回收時(shí)間)

1.Serial收集器是最基本的、發(fā)展歷史最悠久的收集器。

特點(diǎn): 單線程、簡(jiǎn)單高效(與其他收集器的單線程相比),對(duì)于限定單個(gè)CPU的環(huán)境來(lái)說(shuō),Serial收集器 由于沒(méi)有線程交互的開(kāi)銷(xiāo),專(zhuān)心做垃圾收集自然可以獲得最高的單線程手機(jī)效率。收集器進(jìn)行垃圾回收 時(shí),必須暫停其他所有的工作線程,直到它結(jié)束(Stop The World)。

應(yīng)用場(chǎng)景: 適用于Client模式下的虛擬機(jī)。

Serial / Serial Old收集器運(yùn)行示意圖:

2.ParNew收集器其實(shí)就是Serial收集器的多線程版本。

除了使用多線程外其余行為均和Serial收集器一模一樣(參數(shù)控制、收集算法、Stop The World、對(duì)象分配規(guī)則、回收策略等)。

特點(diǎn): 多線程、ParNew收集器默認(rèn)開(kāi)啟的收集線程數(shù)與CPU的數(shù)量相同,在CPU非常多的環(huán)境中,可以 使用-XX:ParallelGCThreads參數(shù)來(lái)限制垃圾收集的線程數(shù)。

和Serial收集器一樣存在Stop The World問(wèn)題

應(yīng)用場(chǎng)景: ParNew收集器是許多運(yùn)行在Server模式下的虛擬機(jī)中首選的新生代收集器,因?yàn)樗浅? Serial收集器外,唯一一個(gè)能與CMS收集器配合工作的。

ParNew/Serial Old組合收集器運(yùn)行示意圖如下:

3.Parallel Scavenge 收集器與吞吐量關(guān)系密切,故也稱(chēng)為吞吐量?jī)?yōu)先收集器。

特點(diǎn): 屬于新生代收集器也是采用復(fù)制算法的收集器,又是并行的多線程收集器(與ParNew收集器類(lèi) 似)。該收集器的目標(biāo)是達(dá)到一個(gè)可控制的吞吐量。還有一個(gè)值得關(guān)注的點(diǎn)是:GC自適應(yīng)調(diào)節(jié)策略(與 ParNew收集器最重要的一個(gè)區(qū)別)

GC自適應(yīng)調(diào)節(jié)策略: Parallel Scavenge收集器可設(shè)置-XX:+UseAdptiveSizePolicy參數(shù)。當(dāng)開(kāi)關(guān)打開(kāi)時(shí)不需要手動(dòng)指定新生代的大小(-Xmn)、Eden與Survivor區(qū)的比例(-XX:SurvivorRation)、晉升老年代 的對(duì)象年齡(-XX:PretenureSizeThreshold)等,虛擬機(jī)會(huì)根據(jù)系統(tǒng)的運(yùn)行狀況收集性能監(jiān)控信息,動(dòng) 態(tài)設(shè)置這些參數(shù)以提供最優(yōu)的停頓時(shí)間和最高的吞吐量,這種調(diào)節(jié)方式稱(chēng)為GC的自適應(yīng)調(diào)節(jié)策略。

Parallel Scavenge收集器使用兩個(gè)參數(shù)控制吞吐量:XX:MaxGCPauseMillis 控制最大的垃圾收集停頓時(shí)間 XX:GCRatio 直接設(shè)置吞吐量的大小。

4.Serial Old是Serial收集器的老年代版本。

特點(diǎn): 同樣是單線程收集器,采用標(biāo)記-整理算法。

應(yīng)用場(chǎng)景: 主要也是使用在Client模式下的虛擬機(jī)中。也可在Server模式下使用。Server模式下主要的兩大用途(在后續(xù)中詳細(xì)講解···):

在JDK1.5以及以前的版本中與Parallel Scavenge收集器搭配使用。

作為CMS收集器的后備方案,在并發(fā)收集Concurent Mode Failure時(shí)使用。

Serial / Serial Old收集器工作過(guò)程圖(Serial收集器圖示相同):

5.Parallel Old是Parallel Scavenge收集器的老年代版本。

特點(diǎn): 多線程,采用標(biāo)記-整理算法。

應(yīng)用場(chǎng)景: 注重高吞吐量以及CPU資源敏感的場(chǎng)合,都可以?xún)?yōu)先考慮Parallel Scavenge+Parallel Old 收集器。

6.CMS收集器是一種以獲取最短回收停頓時(shí)間為目標(biāo)的收集器。

特點(diǎn): 基于標(biāo)記-清除算法實(shí)現(xiàn)。并發(fā)收集、低停頓。

應(yīng)用場(chǎng)景: 適用于注重服務(wù)的響應(yīng)速度,希望系統(tǒng)停頓時(shí)間最短,給用戶(hù)帶來(lái)更好的體驗(yàn)等場(chǎng)景下。如web程序、b/s服務(wù)。

CMS收集器的運(yùn)行過(guò)程分為下列4步:

初始標(biāo)記: 標(biāo)記GC Roots能直接到的對(duì)象。速度很快但是仍存在Stop The World問(wèn)題。

并發(fā)標(biāo)記: 進(jìn)行GC Roots Tracing 的過(guò)程,找出存活對(duì)象且用戶(hù)線程可并發(fā)執(zhí)行。

重新標(biāo)記: 為了修正并發(fā)標(biāo)記期間因用戶(hù)程序繼續(xù)運(yùn)行而導(dǎo)致標(biāo)記產(chǎn)生變動(dòng)的那一部分對(duì)象的標(biāo)記記 錄。仍然存在Stop The World問(wèn)題。

并發(fā)清除: 對(duì)標(biāo)記的對(duì)象進(jìn)行清除回收。CMS收集器的內(nèi)存回收過(guò)程是與用戶(hù)線程一起并發(fā)執(zhí)行的。

CMS收集器的工作過(guò)程圖:

CMS收集器的缺點(diǎn):

  • 對(duì)CPU資源非常敏感。
  • 無(wú)法處理浮動(dòng)垃圾,可能出現(xiàn)Concurrent Model Failure失敗而導(dǎo)致另一次Full GC的產(chǎn)生。
  • 因?yàn)椴捎脴?biāo)記-清除算法所以會(huì)存在空間碎片的問(wèn)題,導(dǎo)致大對(duì)象無(wú)法分配空間,不得不提前觸發(fā) 一次Full GC。

7.G1收集器一款面向服務(wù)端應(yīng)用的垃圾收集器。

特點(diǎn)如下:

并行與并發(fā):G1能充分利用多CPU、多核環(huán)境下的硬件優(yōu)勢(shì),使用多個(gè)CPU來(lái)縮短Stop-The-World停頓時(shí)間。部分收集器原本需要停頓Java線程來(lái)執(zhí)行GC動(dòng)作,G1收集器仍然可以通過(guò)并發(fā)的方式讓Java程序繼續(xù)運(yùn)行。

分代收集:G1能夠獨(dú)自管理整個(gè)Java堆,并且采用不同的方式去處理新創(chuàng)建的對(duì)象和已經(jīng)存活了一段時(shí)間、熬過(guò)多次GC的舊對(duì)象以獲取更好的收集效果。

空間整合:G1運(yùn)作期間不會(huì)產(chǎn)生空間碎片,收集后能提供規(guī)整的可用內(nèi)存。

可預(yù)測(cè)的停頓:G1除了追求低停頓外,還能建立可預(yù)測(cè)的停頓時(shí)間模型。能讓使用者明確指定在一個(gè)長(zhǎng)度為M毫秒的時(shí)間段內(nèi),消耗在垃圾收集上的時(shí)間不得超過(guò)N毫秒。

G1收集器運(yùn)行示意圖:

關(guān)于gc的選擇除非應(yīng)用程序有非常嚴(yán)格的暫停時(shí)間要求,否則請(qǐng)先運(yùn)行應(yīng)用程序并允許VM選擇收集器(如果沒(méi)有特別要求。使用VM提供給的默認(rèn)GC就好)。

如有必要,調(diào)整堆大小以提高性能。如果性能仍然不能滿(mǎn)足目標(biāo),請(qǐng)使用以下準(zhǔn)則作為選擇收集器的起點(diǎn):

  • 如果應(yīng)用程序的數(shù)據(jù)集較小(最大約100 MB),則選擇帶有選項(xiàng)-XX:+ UseSerialGC的串行收集器。
  • 如果應(yīng)用程序?qū)⒃趩蝹€(gè)處理器上運(yùn)行,并且沒(méi)有暫停時(shí)間要求,則選擇帶有選項(xiàng)-XX:+UseSerialGC的串行收集器
  • 如果(a)峰值應(yīng)用程序性能是第一要?jiǎng)?wù),并且(b)沒(méi)有暫停時(shí)間要求或可接受一秒或更長(zhǎng)時(shí)間的暫停,則讓VM選擇收集器或使用-XX:+ UseParallelGC選擇并行收集器 。
  • 如果響應(yīng)時(shí)間比整體吞吐量更重要,并且垃圾收集暫停時(shí)間必須保持在大約一秒鐘以?xún)?nèi),則選擇具有-XX:+ UseG1GC。(值得注意的是JDK9中CMS已經(jīng)被Deprecated,不可使用!移除該選項(xiàng))
  • 如果使用的是jdk8,并且堆內(nèi)存達(dá)到了16G,那么推薦使用G1收集器,來(lái)控制每次垃圾收集的時(shí)間。
  • 如果響應(yīng)時(shí)間是高優(yōu)先級(jí),或使用的堆非常大,請(qǐng)使用-XX:UseZGC選擇完全并發(fā)的收集器。(值得注意的是JDK11開(kāi)始可以啟動(dòng)ZGC,但是此時(shí)ZGC具有實(shí)驗(yàn)性質(zhì),在JDK15中
  • [202009發(fā)布]才取消實(shí)驗(yàn)性質(zhì)的標(biāo)簽,可以直接顯示啟用,但是JDK15默認(rèn)GC仍然是G1)

這些準(zhǔn)則僅提供選擇收集器的起點(diǎn),因?yàn)樾阅苋Q于堆的大小,應(yīng)用程序維護(hù)的實(shí)時(shí)數(shù)據(jù)量以及可用處理器的數(shù)量和速度。如果推薦的收集器沒(méi)有達(dá)到所需的性能,則首先嘗試調(diào)整堆和新生代大小以達(dá)到所需的目標(biāo)。如果性能仍然不足,嘗試使用其他收集器總體原則:減少STOP THE WORD時(shí)間,使用并發(fā)收集器(比如CMS+ParNew,G1)來(lái)減少暫停時(shí)間,加快響應(yīng)時(shí)間,并使用并行收集器來(lái)增加多處理器硬件上的總體吞吐量。

7. 簡(jiǎn)述一下Java類(lèi)加載模型?


雙親委派模型在某個(gè)類(lèi)加載器加載class文件時(shí),它首先委托父加載器去加載這個(gè)類(lèi),依次傳遞到頂層類(lèi)加載器(Bootstrap)。如果頂層加載不了(它的搜索范圍中找不到此類(lèi)),子加載器才會(huì)嘗試加載這個(gè)類(lèi)。雙親委派的好處

  • 每一個(gè)類(lèi)都只會(huì)被加載一次,避免了重復(fù)加載
  • 每一個(gè)類(lèi)都會(huì)被盡可能的加載(從引導(dǎo)類(lèi)加載器往下,每個(gè)加載器都可能會(huì)根據(jù)優(yōu)先次序嘗試加載它)
  • 有效避免了某些惡意類(lèi)的加載(比如自定義了Java.lang.Object類(lèi),一般而言在雙親委派模型下會(huì)加載系統(tǒng)的Object類(lèi)而不是自定義的Object類(lèi))

8. JVM8為什么要增加元空間,帶來(lái)什么好處?

原因:

  1. 字符串存在永久代中,容易出現(xiàn)性能問(wèn)題和內(nèi)存溢出。
  2. 類(lèi)及方法的信息等比較難確定其大小,因此對(duì)于永久代的大小指定比較困難,太小容易出現(xiàn)永久代溢 出,太大則容易導(dǎo)致老年代溢出。
  3. 永久代會(huì)為 GC 帶來(lái)不必要的復(fù)雜度,并且回收效率偏低。

元空間的特點(diǎn):

  1. 每個(gè)加載器有專(zhuān)門(mén)的存儲(chǔ)空間。
  2. 不會(huì)單獨(dú)回收某個(gè)類(lèi)。
  3. 元空間里的對(duì)象的位置是固定的。
  4. 如果發(fā)現(xiàn)某個(gè)加載器不再存貨了,會(huì)把相關(guān)的空間整個(gè)回收。

9. 堆G1垃圾收集器有了解么,有什么特點(diǎn)

G1的特點(diǎn):

  1. G1的設(shè)計(jì)原則是"首先收集盡可能多的垃圾(Garbage First)"。因此,G1并不會(huì)等內(nèi)存耗盡(串行、并行)或者快耗盡(CMS)的時(shí)候開(kāi)始垃圾收集,而是在內(nèi)部采用了啟發(fā)式算法,在老年代找出具有高收集收益的分區(qū)進(jìn)行收集。同時(shí)G1可以根據(jù)用戶(hù)設(shè)置的暫停時(shí)間目標(biāo)自動(dòng)調(diào)整年輕代和總堆大小,暫停目標(biāo)越短年輕代空間越小、總空間就越大;
  2. G1采用內(nèi)存分區(qū)(Region)的思路,將內(nèi)存劃分為一個(gè)個(gè)相等大小的內(nèi)存分區(qū),回收時(shí)則以分區(qū)為單位進(jìn)行回收,存活的對(duì)象復(fù)制到另一個(gè)空閑分區(qū)中。由于都是以相等大小的分區(qū)為單位進(jìn)行操作,因此G1天然就是一種壓縮方案(局部壓縮);
  3. G1雖然也是分代收集器,但整個(gè)內(nèi)存分區(qū)不存在物理上的年輕代與老年代的區(qū)別,也不需要完全獨(dú)立的survivor(to space)堆做復(fù)制準(zhǔn)備。G1只有邏輯上的分代概念,或者說(shuō)每個(gè)分區(qū)都可能隨G1的運(yùn)行在不同代之間前后切換;
  4. G1的收集都是STW的,但年輕代和老年代的收集界限比較模糊,采用了混合(mixed)收集的方式。即每次收集既可能只收集年輕代分區(qū)(年輕代收集),也可能在收集年輕代的同時(shí),包含部分老年代分區(qū)(混合收集),這樣即使堆內(nèi)存很大時(shí),也可以限制收集范圍,從而降低停頓。
  5. 因?yàn)镚1建立可預(yù)測(cè)的停頓時(shí)間模型,所以每一次的垃圾回收時(shí)間都可控,那么對(duì)于大堆(16G左右)的垃圾收集會(huì)有明顯優(yōu)勢(shì)

10. 介紹一下垃圾回收算法?

標(biāo)記-清除

缺點(diǎn): 產(chǎn)生內(nèi)存碎片,如上圖,如果清理了兩個(gè)1kb的對(duì)象,再添加一個(gè)2kb的對(duì)象,無(wú)法放入這兩個(gè)位置

標(biāo)記-整理(老年代)

缺點(diǎn):移動(dòng)對(duì)象開(kāi)銷(xiāo)較大

復(fù)制(新生代)

11. Happens-Before規(guī)則?

先行發(fā)生原則(Happens-Before)是判斷數(shù)據(jù)是否存在競(jìng)爭(zhēng)、線程是否安全的主要依據(jù)。先行發(fā)生是Java內(nèi)存,模型中定義的兩項(xiàng)操作之間的偏序關(guān)系,如果操作A先行發(fā)生于操作B,那么操作A產(chǎn)生的影響能夠被操作B觀察到。

口訣:如果兩個(gè)操作之間具有happen-before關(guān)系,那么前一個(gè)操作的結(jié)果就會(huì)對(duì)后面的一個(gè)操作可見(jiàn)。是Java內(nèi)存模型中定義的兩個(gè)操作之間的偏序關(guān)系。

常見(jiàn)的happen-before規(guī)則:

1.程序順序規(guī)則:一個(gè)線程中的每個(gè)操作,happen-before在該線程中的任意后續(xù)操作。(注解:如果只有一個(gè)線程的操作,那么前一個(gè)操作的結(jié)果肯定會(huì)對(duì)后續(xù)的操作可見(jiàn)。)程序順序規(guī)則中所說(shuō)的每個(gè)操作happen-before于該線程中的任意后續(xù)操作并不是說(shuō)前一個(gè)操作必須要在后一個(gè)操作之前執(zhí)行,而是指前一個(gè)操作的執(zhí)行結(jié)果必須對(duì)后一個(gè)操作可見(jiàn),如果不滿(mǎn)足這個(gè)要求那就不允許這兩個(gè)操作進(jìn)行重排序

2.鎖規(guī)則:對(duì)一個(gè)鎖的解鎖,happen-before在隨后對(duì)這個(gè)鎖加鎖。(注解:這個(gè)最常見(jiàn)的就是synchronized方法和syncronized塊)

3.volatile變量規(guī)則:對(duì)一個(gè)volatile域的寫(xiě),happen-before在任意后續(xù)對(duì)這個(gè)volatile域的讀。該規(guī)則在CurrentHashMap的讀操作中不需要加鎖有很好的體現(xiàn)。

4.傳遞性:如果A happen-before B,且B happen-before C,那么A happen - before C.

5.線程啟動(dòng)規(guī)則:Thread對(duì)象的start()方法happen-before此線程的每一個(gè)動(dòng)作。

6.線程終止規(guī)則:線程的所有操作都happen-before對(duì)此線程的終止檢測(cè),可以通過(guò)Thread.join()方法結(jié)束,Thread.isAlive()的返回值等手段檢測(cè)到線程已經(jīng)終止執(zhí)行。

7.線程中斷規(guī)則:對(duì)線程interrupt()方法的調(diào)用happen-before發(fā)生于被中斷線程的代碼檢測(cè)到中斷時(shí)事件的發(fā)生。

12. 描述一下java類(lèi)加載和初始化的過(guò)程?

JAVA類(lèi)的加載機(jī)制:Java類(lèi)加載分為5個(gè)過(guò)程,分別為:加載,鏈接(驗(yàn)證,準(zhǔn)備,解析),初始化,使用,卸載。

加載:加載主要是將.class文件通過(guò)二進(jìn)制字節(jié)流讀入到JVM中。在加載階段,JVM需要完成3件事:1)通過(guò)classloader在classpath中獲取XXX.class文件,將其以二進(jìn)制流的形式讀入內(nèi)存。2)將字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu);3)在內(nèi)存中生成一個(gè)該類(lèi)的java.lang.Class對(duì)象,作為方法區(qū)這個(gè)類(lèi)的各種數(shù)據(jù)的訪問(wèn)入口。

鏈接

2.1. 驗(yàn)證 主要確保加載進(jìn)來(lái)的字節(jié)流符合JVM規(guī)范。驗(yàn)證階段會(huì)完成以下4個(gè)階段的檢驗(yàn)動(dòng)作:

1)文件格式驗(yàn)證

2)元數(shù)據(jù)驗(yàn)證(是否符合Java語(yǔ)言規(guī)范)

3)字節(jié)碼驗(yàn)證(確定程序語(yǔ)義合法,符合邏輯)

4)符號(hào)引用驗(yàn)證(確保下一步的解析能正常執(zhí)行

2.2. 準(zhǔn)備 準(zhǔn)備是連接階段的第二步,主要為靜態(tài)變量在方法區(qū)分配內(nèi)存,并設(shè)置默認(rèn)初始值。

2.3. 解析 解析是連接階段的第三步,是虛擬機(jī)將常量池內(nèi)的符號(hào)引用替換為直接引用的過(guò)程。

初始化 初始化階段是類(lèi)加載過(guò)程的最后一步,主要是根據(jù)程序中的賦值語(yǔ)句主動(dòng)為類(lèi)變量賦值。當(dāng)有繼承關(guān)系時(shí),先初始化父類(lèi)再初始化子類(lèi),所以創(chuàng)建一個(gè)子類(lèi)時(shí)其實(shí)內(nèi)存中存在兩個(gè)對(duì)象實(shí) 例。

使用 程序之間的相互調(diào)用。

卸載 即銷(xiāo)毀一個(gè)對(duì)象,一般情況下中有JVM垃圾回收器完成。代碼層面的銷(xiāo)毀只是將引用置為null。

13. 吞吐量?jī)?yōu)先和響應(yīng)時(shí)間優(yōu)先的回收器是哪些?

  • 吞吐量?jī)?yōu)先:Parallel Scavenge+Parallel Old(多線程并行)
  • 響應(yīng)時(shí)間優(yōu)先:cms+par new(并發(fā)回收垃圾)

14. 什么叫做阻塞隊(duì)列的有界和無(wú)界,實(shí)際中有用過(guò)嗎?

  • ArrayBlockingQueue:一個(gè)由數(shù)組結(jié)構(gòu)組成的有界阻塞隊(duì)列,線程池,生產(chǎn)者消費(fèi)者
  • LinkedBlockingQueue:一個(gè)由鏈表結(jié)構(gòu)組成的無(wú)界阻塞隊(duì)列,線程池,生產(chǎn)者消費(fèi)者
  • PriorityBlockingQueue:一個(gè)支持優(yōu)先級(jí)排序的無(wú)界阻塞隊(duì)列,可以實(shí)現(xiàn)精確的定時(shí)任務(wù)
  • DelayQueue:一個(gè)使用優(yōu)先級(jí)隊(duì)列實(shí)現(xiàn)的無(wú)界阻塞隊(duì)列,可以實(shí)現(xiàn)精確的定時(shí)任務(wù)
  • SynchronousQueue:一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列,線程池
  • LinkedTransferQueue:一個(gè)由鏈表結(jié)構(gòu)組成的無(wú)界阻塞隊(duì)列
  • LinkedBlockingDeque:一個(gè)由鏈表結(jié)構(gòu)組成的雙向無(wú)界阻塞隊(duì)列,可以用在“工作竊取”模式 中

15. jvm監(jiān)控系統(tǒng)是通過(guò)jmx做的么?

一般都是,但是要是記錄比較詳細(xì)的性能定位指標(biāo),都會(huì)導(dǎo)致進(jìn)入 safepoint,從而降低了線上應(yīng)用性能例如 jstack,jmap打印堆棧,打印內(nèi)存使用情況,都會(huì)讓 jvm 進(jìn)入safepoint,才能獲取線程穩(wěn)定狀態(tài)從而采集信息。同時(shí),JMX暴露向外的接口采集信息,例如使用jvisualvm,還會(huì)涉及rpc和網(wǎng)絡(luò)消耗,以及JVM忙時(shí),無(wú)法采集到信息從而有指標(biāo)斷點(diǎn)。這些都是基于 JMX 的外部監(jiān)控很難解決的問(wèn)題。所以,推薦使用JVM內(nèi)部采集 JFR,這樣即使在JVM很忙時(shí),也能采集到有用的信息

16. 內(nèi)存屏障的匯編指令是啥?

  1. 硬件內(nèi)存屏障 X86
  2. sfence: store| 在sfence指令前的寫(xiě)操作當(dāng)必須在sfence指令后的寫(xiě)操作前完成。
  3. lfence: load | 在lfence指令前的讀操作當(dāng)必須在lfence指令后的讀操作前完成。
  4. mfence: modify/mix | 在mfence指令前的讀寫(xiě)操作當(dāng)必須在mfence指令后的讀寫(xiě)操作前完成。2.原子指令,如x86上的”lock …” 指令是一個(gè)Full Barrier,執(zhí)行時(shí)會(huì)鎖住內(nèi)存子系統(tǒng)來(lái)確保執(zhí)行順序,甚至跨多個(gè)CPU。Software Locks通常使用了內(nèi)存屏障或原子指令來(lái)實(shí)現(xiàn)變量可見(jiàn)性和保持程序順序。3.JVM級(jí)別如何規(guī)范(JSR133)

LoadLoad屏障:對(duì)于這樣的語(yǔ)句Load1; LoadLoad; Load2, 在Load2及后續(xù)讀取操作要讀取的數(shù)據(jù)被訪問(wèn)前,保證Load1要讀取的數(shù)據(jù)被讀取完畢。

StoreStore屏障:對(duì)于這樣的語(yǔ)句Store1; StoreStore; Store2, 在Store2及后續(xù)寫(xiě)入操作執(zhí)行前,保證Store1的寫(xiě)入操作對(duì)其它處理器可見(jiàn)。

LoadStore屏障:對(duì)于這樣的語(yǔ)句Load1; LoadStore; Store2, 在Store2及后續(xù)寫(xiě)入操作被刷出前,保證Load1要讀取的數(shù)據(jù)被讀取完畢。

StoreLoad屏障:對(duì)于這樣的語(yǔ)句Store1; StoreLoad; Load2, 在Load2及后續(xù)所有讀取操作執(zhí)行前,保證Store1的寫(xiě)入對(duì)所有處理器可見(jiàn)。

本文轉(zhuǎn)載自微信公眾號(hào)「 牧小農(nóng)」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系 牧小農(nóng)公眾號(hào)。

 

責(zé)任編輯:姜華 來(lái)源: 牧小農(nóng)
相關(guān)推薦

2021-06-03 08:32:18

JVM調(diào)優(yōu)虛擬機(jī)

2021-03-16 05:44:26

JVM面試題運(yùn)行時(shí)數(shù)據(jù)

2019-11-12 13:16:37

GitHub代碼開(kāi)發(fā)者

2021-08-27 10:14:22

機(jī)器學(xué)習(xí)工具手冊(cè)人工智能

2021-02-25 07:21:00

JVMJavaava虛擬機(jī)

2021-06-01 09:29:43

ArthasJVM內(nèi)存

2020-04-14 10:50:47

FlutterGithub

2021-05-25 09:56:42

Jvm類(lèi)加載機(jī)制Java

2021-02-28 11:58:33

JVM機(jī)制語(yǔ)言

2017-05-15 12:58:00

編程javaapl

2021-02-26 10:16:55

鴻蒙HarmonyOS應(yīng)用開(kāi)發(fā)

2017-10-17 12:43:17

前端CSS布局

2023-10-08 15:23:12

2021-06-02 09:55:20

JVM排查JVM內(nèi)存過(guò)高技術(shù)

2021-11-03 16:10:16

RedisJava內(nèi)存

2018-10-25 09:37:02

Docker入門(mén)容器

2024-08-28 11:56:33

2023-01-11 08:24:32

2018-11-05 08:10:30

Netty架構(gòu)模型

2020-11-23 07:08:17

JVM逃逸元空間
點(diǎn)贊
收藏

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