<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一文掌握 JVM 面試要點(diǎn)

          共 9456字,需瀏覽 19分鐘

           ·

          2022-05-28 17:18

          之前發(fā)表的「吃透MySQL系列」專欄與「吃透Redis系列」專欄收到很多小伙伴的來(lái)信,回饋效果都很好。但是反應(yīng)關(guān)于JVM的文章很少。

          因此,我打算開一個(gè)「吃透JVM系列」的專欄。

          之前發(fā)過(guò)一篇關(guān)于JVM面試知識(shí)點(diǎn)總結(jié)的文章。但是缺乏系統(tǒng)每個(gè)知識(shí)點(diǎn)的講解,于是我打算以那篇文章為目錄根據(jù)每個(gè)知識(shí)點(diǎn)后面為大家詳細(xì)講解,不過(guò)需要等吃透MySQL系列講解完。

          今天,先公布之前JVM面試總結(jié)的修訂版,并給大家預(yù)先宣傳一波,「關(guān)注公眾號(hào),持續(xù)閱讀后續(xù)精彩好文」。

          本文將作為本專欄「吃透Redis系列」目錄,也是大廠面試標(biāo)準(zhǔn)回答,具體每個(gè)點(diǎn)的詳細(xì)解析會(huì)收錄于本專欄,關(guān)注【小龍coding】,持續(xù)閱

          讀后續(xù)精品文章!!

          ?

          本文收錄于【面試筆記】,更多付費(fèi)文章,可以后臺(tái)回復(fù)【面試筆記】獲取,【點(diǎn)擊此處試讀】。

          ?

          1、運(yùn)行時(shí)數(shù)據(jù)區(qū)域

          「堆」

          對(duì)象實(shí)例、數(shù)組

          -Xms表示堆初始大小

          -Xmx表示堆最大大小

          邏輯上連續(xù),線程共享,虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建,最大

          沒(méi)有內(nèi)存完成實(shí)例分配,且無(wú)法擴(kuò)展,OOM

          「方法區(qū)」

          存儲(chǔ)已被虛擬機(jī)加載的類型信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼緩存

          被線程共享,不會(huì)頻繁GC

          「實(shí)現(xiàn)」:jdk7把靜態(tài)變量和字符串常量池移到堆中,jdk8移除永久代,把方法區(qū)移致元空間,它位于本地內(nèi)存。

          ?

          注意:JDk6、JDk7方法區(qū)即PermGen(永久代),JDK8方法區(qū)就是MetaSpace(元空間)

          ?

          運(yùn)行時(shí)常量池:

          「Class文件存放什么:」

          類的版本、字段、方法、接口

          常量池表(Constant pool)(存放編譯期生成的各種「字面量」「符號(hào)引用」

          • 「字面量」:字面量就是指由字母、數(shù)字等構(gòu)成的字符串或者數(shù)值常量
          • 「符號(hào)引用」:類和接口的全限定類名+字段的名稱與描述符+方法的名稱與描述符
          int?a?=?1;//1、2、“abcdefg”就是字面量
          int b = 2;//a b c d字段名就是符號(hào)引用,還有方法名、全限定類名等都屬于=符號(hào)引用。
          String?c?=?"abcdefg";
          String?d?=?"abcdefg";

          Class文件存放的常量池表的內(nèi)容將在類加載后存放到方法區(qū)的運(yùn)行時(shí)常量池(「符號(hào)引用轉(zhuǎn)為直接引用」

          「與Class文件常量池區(qū)別」:動(dòng)態(tài)性(可以在運(yùn)行期間將常量放入池(String:intern()))

          「OOM」:常量池?zé)o法申請(qǐng)到內(nèi)存JVM常量池解析見下文

          「Java虛擬機(jī)棧(棧幀組成)」

          局部變量表(存放基本數(shù)據(jù)類型+對(duì)象引用+返回地址)

          操作數(shù)棧

          動(dòng)態(tài)鏈接

          方法出口

          異常:

          • StackOverFlowError:線程請(qǐng)求的棧深度大于虛擬機(jī)允許的

          • OOM:棧容量動(dòng)態(tài)擴(kuò)展無(wú)足夠內(nèi)存

          • 命令參數(shù):java -Xss2M stackjava

          「本地方法棧」

          為虛擬機(jī)使用到的Native方法服務(wù)

          「程序計(jì)數(shù)器」

          當(dāng)前執(zhí)行的字節(jié)碼指令,「唯一沒(méi)有OOM的地方」?| 執(zhí)行本地方法時(shí)本地方法計(jì)數(shù)器為NULL |?「線程私有」

          「直接內(nèi)存」

          2、對(duì)象的創(chuàng)建五種方式

          2.1、new-構(gòu)造函數(shù)

          2.2、Class類的newInstance方法-構(gòu)造函數(shù)?「(相當(dāng)于用無(wú)參構(gòu)造」

          2.3、Constructor類的newInstance方法-構(gòu)造函數(shù)

          (「bClass.getConstructors() 可以按順序獲取所有構(gòu)造函數(shù)」

          2.4、反序列化

          2.5、clone

          「代碼:」

          Constructor相關(guān)

          ?Class?bClass?=?B.class;
          ?B?b?=?bClass.newInstance();
          ?System.out.println(b.getName());
          ?Constructor?constructor[]=?(Constructor[])?bClass.getConstructors();
          ?B?b1?=?constructor[0].newInstance("11",22);
          ?System.out.println(b1.getName()+b1.getAge());

          反序列化

          //序列化過(guò)程?B需要實(shí)現(xiàn)序列化接口
          ?ObjectOutputStream?objectOutputStream=new?ObjectOutputStream(new?FileOutputStream("b.txt"));
          ?objectOutputStream.writeObject(new?B("11",2));
          ?objectOutputStream.close();
          ?//反序列化
          ?ObjectInputStream?objectInputStream=new?ObjectInputStream(new?FileInputStream("b.txt"));
          ?B?b?=?(B)objectInputStream.readObject();
          ?System.out.println(b.getName()+b.getAge());

          3、對(duì)象創(chuàng)建過(guò)程

          1、當(dāng)虛擬機(jī)遇到一條字節(jié)碼new指令時(shí),首先去檢查這個(gè)指令的參數(shù)是否能在常量池中定位到一個(gè)類的符號(hào)引用,檢查這個(gè)符號(hào)引用代表的類是否被加載過(guò),若沒(méi)有執(zhí)行相關(guān)類加載過(guò)程。「//類加載檢查」

          2、類加載通過(guò)后分配內(nèi)存,若堆內(nèi)存規(guī)整,執(zhí)行指針碰撞分配內(nèi)存,否則使用空閑列表分配;「//分配內(nèi)存」

          3、劃分內(nèi)存還需要考慮并發(fā)問(wèn)題,可以CAS同步處理,或則本地線程分配緩沖。「//并發(fā)問(wèn)題處理」

          4、然后內(nèi)存空間初始化操作(默認(rèn)值,一)些必要的對(duì)象設(shè)置(元信息、哈希碼),再行init()方法(按照程序員意愿初始化)。

          4、對(duì)象的訪問(wèn)定位

          「句柄:「指針的指針。堆劃分一塊內(nèi)存作為句柄池(句柄池+實(shí)例池),引用存儲(chǔ)句柄的地址,句柄中包含了」對(duì)象實(shí)例數(shù)據(jù)指針」(指向堆對(duì)象實(shí)例數(shù)據(jù))+「對(duì)象實(shí)例類型指針」(指向方法區(qū)對(duì)象類型數(shù)據(jù))

          • 優(yōu)點(diǎn):穩(wěn)定,對(duì)象移動(dòng)時(shí)只改變句柄中對(duì)象實(shí)例數(shù)據(jù)指針,而引用本身不變指向句柄

          「直接指針」:直接指向?qū)ο?,保存?duì)象內(nèi)存起始地址的指針

          • 優(yōu)點(diǎn):訪問(wèn)速度快,一次定位

          5、對(duì)象內(nèi)存分配

          「指針碰撞」

          堆內(nèi)存規(guī)整,將堆分為空閑和使用過(guò)兩部分,空閑的放一邊,用過(guò)的放一邊,中間放一個(gè)指針指向分界處,分配對(duì)象內(nèi)存時(shí)就將指針向空閑部分移動(dòng)相應(yīng)大小

          「空閑列表」

          堆內(nèi)存不規(guī)整,需借助列表存放可用空間,分配對(duì)象內(nèi)存時(shí)查看列表找到足夠的空間分配給對(duì)象,并更新列表

          6、對(duì)象并發(fā)安全問(wèn)題

          「分配內(nèi)存需考慮并發(fā)問(wèn)題」:可能正在給對(duì)象A分配內(nèi)存,指針還沒(méi)來(lái)得及修改,對(duì)象B又同時(shí)使用了原來(lái)的指針來(lái)分配內(nèi)存的情況

          「CAS+失敗重試保證更新原子性」:對(duì)分配內(nèi)存空間動(dòng)作進(jìn)行同步處理

          「本地線程分配緩沖」:每個(gè)線程在Java堆中預(yù)先分配一小塊內(nèi)存(本地線程分配緩沖)哪個(gè)線程要分配內(nèi)存,就在哪個(gè)線程的本地緩沖區(qū)中分配,本地緩沖區(qū)用完了分配新的緩沖區(qū)才需要同步鎖定

          7、對(duì)象內(nèi)存布局

          java對(duì)象=對(duì)象頭+實(shí)例數(shù)據(jù)+對(duì)齊填充

          對(duì)象頭=Mark Word+ 對(duì)象所屬類 的指針組成(如果是數(shù)組對(duì)象,還會(huì)包含長(zhǎng)度)

          Mark Word=存儲(chǔ)對(duì)象自身的運(yùn)行時(shí)數(shù)據(jù),例如hashCode,GC分代年齡,鎖狀態(tài)標(biāo)志,線程持有的鎖等等

          8、OOM異常

          JVM堆,無(wú)法給實(shí)例分配內(nèi)存,且無(wú)法擴(kuò)展時(shí),OOM。

          方法區(qū)(以及運(yùn)行時(shí)常量池)無(wú)法滿足內(nèi)存分配需求時(shí),OOM.

          Java虛擬機(jī)棧+本地方法棧,擴(kuò)展時(shí)無(wú)法申請(qǐng)到足夠內(nèi)存,OOM(線程請(qǐng)求深度超過(guò)JVM允許棧深度,StackOverflowException).

          9、內(nèi)存泄漏與內(nèi)存溢出

          無(wú)用內(nèi)存得不到釋放。程序申請(qǐng)了內(nèi)存,使用完后又不能歸還JVM,造成內(nèi)存泄漏,內(nèi)存泄漏多了就造成內(nèi)存溢出。內(nèi)存溢出——》

          OOM(內(nèi)存滿了,沒(méi)有內(nèi)存給實(shí)例分配空間,且無(wú)法擴(kuò)展)

          Student?stu=new?Student();
          List?stus=new?ArrayList<>();
          stus.add(stu);
          stu=null;
          stu占用的內(nèi)存得不到釋放,stus占用著student.?發(fā)生內(nèi)存泄漏

          10、判斷對(duì)象是否是垃圾

          「引用計(jì)數(shù)器法:」

          對(duì)象添加一個(gè)引用計(jì)數(shù)器,每當(dāng)有個(gè)引用就加一,引用失效減一,當(dāng)為減為0對(duì)象不可用

          缺點(diǎn):相互引用,A<-->B,然后A、B已經(jīng)沒(méi)有被其他有用對(duì)象引用,本視為垃圾,但是由于互相引用不能被檢查回收。

          「可達(dá)性分析法:」

          從GC Roots到該對(duì)象可達(dá)

          11、GC Roots

          • Java虛擬機(jī)棧(棧幀中的本變量表)中引用的對(duì)象
          • 方法區(qū)「常量、靜態(tài)變量」引用的對(duì)象
          • 本地方法棧JNI引用對(duì)象
          • 所有被同步鎖持有的對(duì)象

          總結(jié)記憶口訣:兩棧一方法

          局部變量表:存放方法參數(shù)和方法內(nèi)部定義的局部變量

          12、四種引用狀態(tài)(強(qiáng)軟弱虛)

          「強(qiáng)引用」

          Object obj=new Object(); StronglyReference ——不會(huì)被回收

          「軟引用」

          new SoftReference(obj); 描述有用但非必須的對(duì)象——內(nèi)存不夠回收

          「弱引用」

          WeakReference ?弱引用一定會(huì)被回收,下一次GC回收

          「虛引用」

          PhantomReference 為了能在這個(gè)對(duì)象被收集器回收時(shí)收到一個(gè)系統(tǒng)通知

          13、方法區(qū)的回收

          「廢棄的常量」

          沒(méi)有被引用

          如:字面量回收

          ?

          一個(gè)字符串“abc”放入常量池,現(xiàn)在沒(méi)有一個(gè)值為"abc"的字符串對(duì)象,也就是 沒(méi)有任何字符串對(duì)象引用常量池中“abc”的常量,且虛擬機(jī)其他地方?jīng)]有引用這個(gè)字面量,如果發(fā)生垃圾回收且有必要時(shí),常量會(huì)被系統(tǒng)清理出常量池 String s1="abc"; Strig s2=new String("abc"); 其他接口,方法,字段,符號(hào)引用類似

          ?

          「無(wú)用類的卸載」

          • 該類的所有實(shí)例被回收,堆中不存在該類及其派生子類的實(shí)例
          • 加載該類的CassLoder被回收
          • 該類對(duì)應(yīng)的java.lang.Class對(duì)象沒(méi)有在任何地方被引用

          14、垃圾收集算法

          「標(biāo)記-清除」

          • 先標(biāo)記后清除,先標(biāo)記垃圾對(duì)象,然后統(tǒng)一回收垃圾對(duì)象
          • 缺點(diǎn):要標(biāo)記和清除,效率不高,還容易出現(xiàn)內(nèi)存碎片化

          「復(fù)制算法」(適用新生代—存活率低)

          • 「對(duì)象存活率高時(shí)會(huì)有大量復(fù)制,效率低」?,老年代存活率高,不適用 |(分配擔(dān)保)
          • 將內(nèi)存容量分為大小相等兩部分,先使用一塊內(nèi)存,用完了將還存活的對(duì)象復(fù)制到另一塊內(nèi)存上。由于內(nèi)存被分為兩部分,使得「只能用一半內(nèi)存」

          「標(biāo)記-整理」

          • 前面和標(biāo)記清除一樣,先標(biāo)記,但是不會(huì)立刻清除,先把「存活的對(duì)象都移到一端」,然后直接清除掉邊界以外的對(duì)象。不會(huì)出現(xiàn)碎片化。

          「分代收集」

          • 堆分為年輕代老年代,新生代存活率低使用復(fù)制算法,老年代存活率高使用標(biāo)記清除/標(biāo)記整理。

          15、垃圾收集器

          「注重低延遲」

          「CMS」:基于標(biāo)記清除的并發(fā)垃圾收集器

          • 初始標(biāo)記:標(biāo)記GC Roots直達(dá)的對(duì)象(「stw」
          • 并發(fā)標(biāo)記:跟蹤標(biāo)記GC Roots所有可達(dá)對(duì)象
          • 重新標(biāo)記:重新標(biāo)記那些由于并發(fā)標(biāo)記中用戶程序跟到執(zhí)行導(dǎo)致標(biāo)記發(fā)生變化的對(duì)象(「stw」
          • 并發(fā)清除:清除標(biāo)記垃圾

          「優(yōu)點(diǎn)」:支持并發(fā),停頓時(shí)間短

          「缺點(diǎn)」:使用標(biāo)記清除算法,空間碎片。并發(fā)標(biāo)記產(chǎn)生浮動(dòng)垃圾。

          「G1」:并發(fā)+并行(重新標(biāo)記+篩選回收)

          「弱化分代(老年代與年輕代一起回收),引入分區(qū)。將堆分為多個(gè)大小相等區(qū)域分而治之?!?/strong>

          • 初始標(biāo)記:標(biāo)記GC Roots直達(dá)的對(duì)象,并且修改TAMS(Next Top Mark Start)的值,讓下一階段用戶程序并發(fā)運(yùn)行時(shí),能在正確可以用的Region中創(chuàng)建新對(duì)象,「需要停頓線程,但耗時(shí)很短」
          • 并發(fā)標(biāo)記:跟蹤標(biāo)記GC Roots所有可達(dá)對(duì)象
          • 最終標(biāo)記:修正在并發(fā)標(biāo)記期間因用戶程序繼續(xù)運(yùn)作而導(dǎo)致標(biāo)記產(chǎn)生變動(dòng)的那一部分標(biāo)記記錄,對(duì)象變化記錄在線程Remenbered Set Logs里面,最終標(biāo)記階段需要把Remembered Set Logs的數(shù)據(jù)合并到Remembered Set中,這階段「需要停頓線程」,但可并行執(zhí)行
          • 篩選回收:對(duì)各個(gè)region區(qū)域進(jìn)行回收價(jià)值與成本的排序,根據(jù)用戶期望的GC停頓時(shí)間來(lái)執(zhí)行計(jì)劃(最少時(shí)間回收最多垃圾區(qū)域,停頓用戶線程)

          「特點(diǎn):」

          「空間整合:「整體來(lái)看是基于“標(biāo)記 - 整理”算法實(shí)現(xiàn)的收集器,從局部(兩個(gè) Region 之間)上來(lái)看是基于“復(fù)制”算法實(shí)現(xiàn)的,這意味著運(yùn)行期間不」會(huì)產(chǎn)生內(nèi)存空間碎片」

          「可預(yù)測(cè)的停頓」:能讓使用者明確指定在一個(gè)長(zhǎng)度為 M 毫秒的時(shí)間片段內(nèi),消耗在 GC 上的時(shí)間不得超過(guò) N 毫秒。

          16、G1與CMS區(qū)別

          • 使用范圍:CMS使用在老年代,G1收集范圍新生代與老年代
          • STW的時(shí)間:CMS注重低延遲,G1可預(yù)測(cè)的停頓
          • 垃圾碎片:CMS使用標(biāo)記清除算法,造成內(nèi)存空間碎片;G1進(jìn)行空間整合使用標(biāo)記-整理,不會(huì)有內(nèi)存空間碎片
          • 垃圾回收過(guò)程
          • 使用場(chǎng)景

          「stw」:垃圾回收,暫停所用用戶線程執(zhí)行,避免垃圾回收時(shí)產(chǎn)生新垃圾。

          17、類加載過(guò)程

          • 「加載」:根據(jù)類的全限定類名獲取二進(jìn)制字節(jié)流,將字節(jié)流代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)->運(yùn)行時(shí)存儲(chǔ)結(jié)構(gòu),在內(nèi)存生成「Class對(duì)象」,作為方法區(qū)這個(gè)類數(shù)據(jù)訪問(wèn)入口
          • 「驗(yàn)證」:檢驗(yàn)加載的class文件正確性(修飾符、權(quán)限、)
          • 「準(zhǔn)備」:為類的「靜態(tài)變量」分配內(nèi)存,并賦默認(rèn)值
          • 「解析」:將常量池中符號(hào)引用轉(zhuǎn)為直接引用(class文件常量池轉(zhuǎn)至方法區(qū)運(yùn)行時(shí)常量池)
          • 「初始化」:(針對(duì)類變量初始化)對(duì)靜態(tài)變量和靜態(tài)代碼塊執(zhí)行初始化工作

          18、類加載器

          • 啟動(dòng)類加載器:加載核心類庫(kù)(JAVA_HOME/lib 如rt.jar)
          • 擴(kuò)展類加載器:加載擴(kuò)展類(JAVA_HOME/jre/lib/ext)
          • 系統(tǒng)類加載器:加載用戶類路徑ClassPath下的類
          • 用戶自定義加載器:繼承java.lang.ClassLoader

          19、類加載方式

          • 隱式加載:當(dāng)碰到通過(guò)new 等方式生成對(duì)象時(shí),隱式調(diào)用類裝載器加載對(duì)應(yīng)的類到j(luò)vm中
          • 顯示加載:通過(guò)class.forname()等方法,顯式加載需要的類

          20、雙親委派模型

          含義:類加載請(qǐng)求來(lái)了,類加載器自己先不加載,先讓父類加載器加載,父類不行自己再來(lái)

          「怎樣打破雙親委派機(jī)制:」

          • 自定義類加載器,重寫loadClass方法
          • 線程上下文類加載器

          Java涉及SPI機(jī)制的都用線程上下文類加載器。父類加載器請(qǐng)求子類加載器完成加載動(dòng)作

          SPI機(jī)制:為接口找尋服務(wù)(jdbc)

          ?

          SPI約定:服務(wù)提供者為接口提供接口實(shí)現(xiàn)后,會(huì)在jar包的META-INF/service/目錄下創(chuàng)建一個(gè)以服務(wù)接口命名的文件。

          ?

          JDBC4.0使用SPI機(jī)制,DriverManager需要去jar包下的META-INF/services/java.sql.Driver目錄下去尋找對(duì)應(yīng)的Driver加載,但是

          DriverManager在rt.jar中,使用啟動(dòng)類加載器(BootStrapClassLoader),它需要調(diào)用服務(wù)提供者放在classpath下的類,啟動(dòng)類加載器無(wú)

          法加載,就只得使用線程上下文加載器,讓父類加載器調(diào)用子類加載器完成,打破了雙親委派機(jī)制。

          「好處」:避免類重復(fù)加載+防止核心類篡改+安全性

          21、GC

          Minor GC:回收年輕代

          Major GC :回收老年代

          Full GC:回收年輕代與老年代,方法區(qū)域

          22、內(nèi)存分配與回收策略

          「對(duì)象優(yōu)先在Eden區(qū)分配」

          大多數(shù)情況下,對(duì)象在新生代 Eden 上分配,當(dāng) Eden 空間不夠時(shí),發(fā)起 Minor GC。

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

          大對(duì)象指「需要連續(xù)分配空間」的對(duì)象,長(zhǎng)字符串,數(shù)組。

          對(duì)象過(guò)大,由于需要連續(xù)的內(nèi)存空間,會(huì)導(dǎo)致提前進(jìn)行垃圾回收以獲取足夠的連續(xù)空間 -XX:PretenureSizeThreshold,大于此值的對(duì)象直接在老年代分配,避免在 Eden 和 Survivor 之間的大量?jī)?nèi)存復(fù)制。

          「長(zhǎng)期存活的對(duì)象」

          對(duì)象在Eden區(qū)出生,經(jīng)過(guò)一次Minor GC存活下來(lái),分代年齡就會(huì)加一,增加到一定年齡就會(huì)移向老年代。默認(rèn)是15. -XX:MaxTenuringThreshold用來(lái)定義該年齡的閾值。

          「動(dòng)態(tài)對(duì)象年齡判定」

          虛擬機(jī)并不是永遠(yuǎn)要求對(duì)象的年齡必須達(dá)到MaxTenuringThreshold才能晉升到老年代,當(dāng)「Survivor區(qū)相同年齡的所有對(duì)象大小總和大于Survivork空間一半」,則年齡大于或等于該年齡的對(duì)象直接進(jìn)入老年代,無(wú)需等到 MaxTenuringThreshold 中要求的年齡。

          「空間分配擔(dān)保(*)」

          在發(fā)生 Minor GC 之前,虛擬機(jī)先檢查老年代最大可用的連續(xù)空間是否大于新生代所有對(duì)象總空間,如果條件成立的話,那么 Minor GC 可以確認(rèn)是安全的。

          如果不成立的話虛擬機(jī)會(huì)查看 HandlePromotionFailure 的值是否允許擔(dān)保失敗,如果允許那么就會(huì)繼續(xù)檢查老年代最大可用的連續(xù)空間是否大于歷次晉升到老年代對(duì)象的平均大小。

          如果大于,將嘗試著進(jìn)行一次 Minor GC;如果小于,或者 HandlePromotionFailure 的值不允許冒險(xiǎn),那么就要進(jìn)行一次 Full GC。

          23、分代垃圾收集器是怎樣工作的

          「分代回收器有兩個(gè)分區(qū)」:老生代和新生代,新生代默認(rèn)的空間占比總空間的 1/3,老生代的默認(rèn)占比是 2/3。

          新生代使用的是復(fù)制算法,新生代里有 3 個(gè)分區(qū):Eden、To Survivor、From Survivor,它們的默認(rèn)占比是 8:1:1。

          「它的執(zhí)行流程如下:」

          把 Eden + From Survivor 存活的對(duì)象放入 To Survivor 區(qū);

          清空 Eden 和 From Survivor 分區(qū);

          From Survivor 和 To Survivor 分區(qū)交換,F(xiàn)rom Survivor 變 To Survivor,To Survivor 變 From Survivor。

          每次在 From Survivor 到 To Survivor 移動(dòng)時(shí)都存活的對(duì)象,年齡就 +1,當(dāng)年齡到達(dá) 15(默認(rèn)配置是 15)時(shí),升級(jí)為老生代。「大對(duì)象也會(huì)直接進(jìn)入老生代?!?/strong>

          老生代當(dāng)空間占用到達(dá)某個(gè)值之后就會(huì)觸發(fā)全局垃圾收回,一般使用標(biāo)記整理的執(zhí)行算法。以上這些循環(huán)往復(fù)就構(gòu)成了整個(gè)分代垃圾回收的整體執(zhí)行流程。

          24、Full GC觸發(fā)條件

          對(duì)于 Minor GC,其觸發(fā)條件非常簡(jiǎn)單,當(dāng) Eden 空間滿時(shí),就將觸發(fā)一次 Minor GC。而 Full GC 則相對(duì)復(fù)雜,有以下條件:

          「調(diào)用System.gc()」

          只是建議虛擬機(jī)執(zhí)行 Full GC,但是虛擬機(jī)不一定真正去執(zhí)行。不建議使用這種方式,而是讓虛擬機(jī)管理內(nèi)存。

          「老年代空間不足」

          「場(chǎng)景:」

          大對(duì)象直接進(jìn)入老年代(老年代空間足,但是沒(méi)有足夠的連續(xù)空間) 長(zhǎng)期存活的對(duì)象直接進(jìn)入老年代

          「解決:」

          1、盡量「不要?jiǎng)?chuàng)建過(guò)大的對(duì)象」以及數(shù)組 2、可以通過(guò)-Xmn「調(diào)大新生代大小」,讓「對(duì)象盡量在新生代被回收」,不進(jìn)老年代 3、可以通過(guò)-XX:MaxTenuringThreshold「調(diào)大分代年齡閾值」,讓對(duì)象得新生代多存活一段時(shí)間

          「空間分配擔(dān)保失敗」

          使用復(fù)制算法的 Minor GC 需要老年代的內(nèi)存空間作擔(dān)保,如果擔(dān)保失敗會(huì)執(zhí)行一次 Full GC。

          「解釋一」

          老年代最大可用的連續(xù)空間<新生代所有對(duì)象總空間 && HandlerPromotionFailure設(shè)置不允許擔(dān)保失敗 full gc

          老年代最大可用的連續(xù)空間>新生代所有對(duì)象總空間 && HandlerPromotionFailure設(shè)置允許擔(dān)保失敗 && 通過(guò)Minor GCJ進(jìn)入老年代的象平均大小>老年代最大連續(xù)空間大小 full gc

          「解釋二」

          Minor GC前,先判斷老年代最大連續(xù)空間是否大于新生代所有對(duì)象總空間。

          若大于,安全;若小于,查看HandlerPromotionFailure設(shè)置是否允許擔(dān)保失敗,允許,再看通過(guò)Minor GCJ進(jìn)入老年代的對(duì)象平均大小>老年代最大連續(xù)

          空間太小,則還是失敗,進(jìn)行Full GC。

          「jdk1.7以前的永久代空間不足」

          永久代可能會(huì)被占滿,在未配置為采用 CMS GC 的情況下也會(huì)執(zhí)行 Full GC。如果經(jīng)過(guò) Full GC 仍然回收不了,那么虛擬機(jī)會(huì)拋出 java.lang.OutOfMemoryError。

          為避免以上原因引起的 Full GC,可采用的方法為增大永久代空間或轉(zhuǎn)為使用 CMS GC。

          25、為什么有垃圾收集還會(huì)有內(nèi)存泄漏問(wèn)題?

          「對(duì)象定義在錯(cuò)誤的范圍」如果長(zhǎng)生命周期的對(duì)象持有短生命周期的引用,就很可能會(huì)出現(xiàn)內(nèi)存泄露。「異常處理不當(dāng)」各種資源的關(guān)閉一定要放在finally里面

          26、堆與棧的區(qū)別?

          「申請(qǐng)方式」:棧系統(tǒng)自動(dòng)申請(qǐng),堆需手動(dòng)申請(qǐng)c語(yǔ)言malloc(),java new Object();

          棧系統(tǒng)分配速度快,堆慢,容易內(nèi)部碎片;棧地址空間連續(xù),堆是不連續(xù)的(鏈表存儲(chǔ)空閑內(nèi)存地址);

          「內(nèi)容不一樣」(堆存對(duì)象實(shí)例與數(shù)組,關(guān)注存儲(chǔ);棧存儲(chǔ)局部變量表,操作數(shù)棧,關(guān)注運(yùn)行);

          「大下限制」(棧預(yù)先設(shè)定好的,編譯器即可確定,堆取決有效虛擬內(nèi)存,運(yùn)行期間確定)

          27、逃逸分析

          **概念:**當(dāng)一個(gè)對(duì)象在方法中被定義后,它可能被方法外部其他對(duì)象所引用,則稱逃出方法(內(nèi)存逃逸現(xiàn)象)

          使用逃逸分析,編譯器優(yōu)化

          • 同步省略:對(duì)象沒(méi)有方法逃逸,只能被一個(gè)線程訪問(wèn)到,可以不用同步
          • 「將堆分配轉(zhuǎn)為棧分配」

          如果JIT經(jīng)過(guò)逃逸分析,發(fā)現(xiàn)有些對(duì)象沒(méi)有逃逸出方法,那么有可能堆內(nèi)存分配會(huì)被優(yōu)化成棧內(nèi)存分配

          28、JVM參數(shù)

          • -Xmx3550:設(shè)置堆最大值
          • -Xms3660m:設(shè)置初始堆大小
          • -Xss128k:設(shè)置線程棧大小
          • -Xmn2g:設(shè)置年輕代大小
          • -XX:NewSize=1024m:設(shè)置年輕代初始值
          • -XX:MaxNewSize=1024m:設(shè)置年輕代最大值
          • -XX:SurvivorRatio=4:設(shè)置Survivor區(qū)與Eden區(qū)比值
          • -XX:MaxTenuringThreshold=15:設(shè)置分代年齡閾值,滿15就進(jìn)入老年代
          • -XX:PretenureSizeThreshold:大對(duì)象直接進(jìn)入老年代

          29、內(nèi)存持續(xù)上升,我該如何處理

          1、啟動(dòng)程序之前通過(guò) HeapDumpOnOutOfMemoryError 和 HeapDumpPath 這兩個(gè)參數(shù)「開啟堆內(nèi)存異常日志」

          -XX:+HeapDumpOnOutOfMemoryError?-XX:HeapDumpPath=

          2、從日志從發(fā)現(xiàn)異常

          3、通過(guò)top命令查看進(jìn)程cpu使用率

          4、再通過(guò) top -Hp pid 查看進(jìn)程下所有「具體線程占用系統(tǒng)資源情況」

          5、再通過(guò) jstack pid 查看具體線程的「堆棧信息」(線程ID、狀態(tài)(wait,sleep),是否持有鎖)

          6、再通過(guò) jmap 查看「堆內(nèi)存的使用情況」?jmap -heap pid

          7、通過(guò)以上命令分析基本可以看出什么問(wèn)題導(dǎo)致內(nèi)存上升,現(xiàn)在分析問(wèn)題產(chǎn)生的原因

          8、我們?cè)趩?dòng)時(shí),已經(jīng)設(shè)置了 dump 文件,通過(guò) MAT 打開 dump 的內(nèi)存日志文件,分析即可。

          須知

          30、JVM性能調(diào)優(yōu)與故障處理
          31、基本故障處理工具
          32、可視化故障處理工具

          最后三節(jié),屬于進(jìn)階內(nèi)容,前面基礎(chǔ)一定要掌握好。由于篇幅有限,關(guān)注公眾號(hào),后期會(huì)專門針對(duì)大廠面試常問(wèn)性能調(diào)優(yōu)與工具進(jìn)行講解。

          后記

          關(guān)注我公眾號(hào)“小龍coding”,我們一起探討,幫助修改簡(jiǎn)歷,回答疑問(wèn),項(xiàng)目分析,只為幫助迷茫的你高效斬獲心儀offer!

          后續(xù)會(huì)陸續(xù)更新大廠面經(jīng)面試題與解析,大廠內(nèi)推「直達(dá)部門主管」,也有交流群大家一起探討共同進(jìn)步。加油噢!


          瀏覽 46
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    欧美v日韩v亚洲 | 国产精品免费在线 | 加勒比无码在线播放 | 天堂AV中文 | 免费一区二区三区四区五区 |