Java程序員跳槽漲薪必備——阿里面試官分享25道JVM面試題

一. 什么是Java虛擬機?為什么Java被稱作是“平臺無關的編程語言”郁妈?

Java虛擬機是一個可以執(zhí)行Java字節(jié)碼的虛擬機進程。Java源文件被編譯成能被Java虛擬機執(zhí)行的字節(jié)碼文件焙压。 Java被設計成允許應用程序可以運行在任意的平臺后专,而不需要程序員為每一個平臺單獨重寫或者是重新編譯。Java虛擬機讓這個變?yōu)榭赡苊榔郑驗樗赖讓佑布脚_的指令長度和其他特性。

二. Java內(nèi)存結(jié)構(gòu)项栏?

方法區(qū)和堆是所有線程共享的內(nèi)存區(qū)域浦辨;而java棧、本地方法棧和程序員計數(shù)器是運行是線程私有的內(nèi)存區(qū)域。

  • Java堆(Heap),是Java虛擬機所管理的內(nèi)存中最大的一塊流酬。Java堆是被所有線程共享的一塊內(nèi)存區(qū)域币厕,在虛擬機啟動時創(chuàng)建。此內(nèi)存區(qū)域的唯一目的就是存放對象實例芽腾,幾乎所有的對象實例都在這里分配內(nèi)存旦装。
  • 方法區(qū)(Method Area),方法區(qū)(Method Area)與Java堆一樣,是各個線程共享的內(nèi)存區(qū)域摊滔,它用于存儲已被虛擬機加載的類信息阴绢、常量、靜態(tài)變量艰躺、即時編譯器編譯后的代碼等數(shù)據(jù)呻袭。
  • 程序計數(shù)器(Program Counter Register),程序計數(shù)器(Program Counter Register)是一塊較小的內(nèi)存空間,它的作用可以看做是當前線程所執(zhí)行的字節(jié)碼的行號指示器腺兴。
  • JVM棧(JVM Stacks),與程序計數(shù)器一樣左电,Java虛擬機棧(Java Virtual Machine Stacks)也是線程私有的,它的生命周期與線程相同页响。虛擬機棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個方法被執(zhí)行的時候都會同時創(chuàng)建一個棧幀(Stack Frame)用于存儲局部變量表篓足、操作棧、動態(tài)鏈接闰蚕、方法出口等信息栈拖。每一個方法被調(diào)用直至執(zhí)行完成的過程,就對應著一個棧幀在虛擬機棧中從入棧到出棧的過程陪腌。
  • 本地方法棧(Native Method Stacks),本地方法棧(Native Method Stacks)與虛擬機棧所發(fā)揮的作用是非常相似的辱魁,其區(qū)別不過是虛擬機棧為虛擬機執(zhí)行Java方法(也就是字節(jié)碼)服務,而本地方法棧則是為虛擬機使用到的Native方法服務诗鸭。

三. 解釋內(nèi)存中的棧(stack)染簇、堆(heap)和方法區(qū)(method area)的用法

通常我們定義一個基本數(shù)據(jù)類型的變量,一個對象的引用强岸,還有就是函數(shù)調(diào)用的現(xiàn)場保存都使用JVM中的椂凸空間;而通過new關鍵字和構(gòu)造器創(chuàng)建的對象則放在堆空間蝌箍,堆是垃圾收集器管理的主要區(qū)域青灼,由于現(xiàn)在的垃圾收集器都采用分代收集算法,所以堆空間還可以細分為新生代和老生代妓盲,再具體一點可以分為Eden杂拨、Survivor(又可分為From Survivor和To Survivor)、Tenured悯衬;方法區(qū)和堆都是各個線程共享的內(nèi)存區(qū)域弹沽,用于存儲已經(jīng)被JVM加載的類信息、常量、靜態(tài)變量策橘、JIT編譯器編譯后的代碼等數(shù)據(jù)炸渡;程序中的字面量(literal)如直接書寫的100、"hello"和常量都是放在常量池中丽已,常量池是方法區(qū)的一部分蚌堵,。椗嬗ぃ空間操作起來最快但是棧很小吼畏,通常大量的對象都是放在堆空間,棧和堆的大小都可以通過JVM的啟動參數(shù)來進行調(diào)整瘸味,椆蹋空間用光了會引發(fā)StackOverflowError,而堆和常量池空間不足則會引發(fā)OutOfMemoryError旁仿。

String str = new String("hello");

上面的語句中變量str放在棧上藕夫,用new創(chuàng)建出來的字符串對象放在堆上,而"hello"這個字面量是放在方法區(qū)的枯冈。

補充1:較新版本的Java(從Java 6的某個更新開始)中毅贮,由于JIT編譯器的發(fā)展和"逃逸分析"技術(shù)的逐漸成熟,棧上分配尘奏、標量替換等優(yōu)化技術(shù)使得對象一定分配在堆上這件事情已經(jīng)變得不那么絕對了滩褥。

補充2:運行時常量池相當于Class文件常量池具有動態(tài)性,Java語言并不要求常量一定只有編譯期間才能產(chǎn)生炫加,運行期間也可以將新的常量放入池中瑰煎,String類的intern()方法就是這樣的。 看看下面代碼的執(zhí)行結(jié)果是什么并且比較一下Java 7以前和以后的運行結(jié)果是否一致俗孝。

String s1 = new StringBuilder("go")
    .append("od").toString();
System.out.println(s1.intern() == s1);
String s2 = new StringBuilder("ja")
    .append("va").toString();
System.out.println(s2.intern() == s2);

四. 對象分配規(guī)則

  • 對象優(yōu)先分配在Eden區(qū)酒甸,如果Eden區(qū)沒有足夠的空間時,虛擬機執(zhí)行一次Minor GC赋铝。
  • 大對象直接進入老年代(大對象是指需要大量連續(xù)內(nèi)存空間的對象)插勤。這樣做的目的是避免在Eden區(qū)和兩個Survivor區(qū)之間發(fā)生大量的內(nèi)存拷貝(新生代采用復制算法收集內(nèi)存)。
  • 長期存活的對象進入老年代革骨。虛擬機為每個對象定義了一個年齡計數(shù)器农尖,如果對象經(jīng)過了1次Minor GC那么對象會進入Survivor區(qū),之后每經(jīng)過一次Minor GC那么對象的年齡加1良哲,知道達到閥值對象進入老年區(qū)盛卡。
  • 動態(tài)判斷對象的年齡。如果Survivor區(qū)中相同年齡的所有對象大小的總和大于Survivor空間的一半筑凫,年齡大于或等于該年齡的對象可以直接進入老年代窟扑。
  • 空間分配擔保喇颁。每次進行Minor GC時,JVM會計算Survivor區(qū)移至老年區(qū)的對象的平均大小嚎货,如果這個值大于老年區(qū)的剩余值大小則進行一次Full GC,如果小于檢查HandlePromotionFailure設置蔫浆,如果true則只進行Monitor GC,如果false則進行Full GC殖属。

五. 什么是類的加載

類的加載指的是將類的.class文件中的二進制數(shù)據(jù)讀入到內(nèi)存中,將其放在運行時數(shù)據(jù)區(qū)的方法區(qū)內(nèi)瓦盛,然后在堆區(qū)創(chuàng)建一個java.lang.Class對象洗显,用來封裝類在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)。類的加載的最終產(chǎn)品是位于堆區(qū)中的Class對象原环,Class對象封裝了類在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)挠唆,并且向Java程序員提供了訪問方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)的接口。

六. 類加載器

  • 啟動類加載器:Bootstrap ClassLoader嘱吗,負責加載存放在JDK\jre\lib(JDK代表JDK的安裝目錄玄组,下同)下,或被-Xbootclasspath參數(shù)指定的路徑中的谒麦,并且能被虛擬機識別的類庫
  • 擴展類加載器:Extension ClassLoader俄讹,該加載器由sun.misc.Launcher$ExtClassLoader實現(xiàn),它負責加載DK\jre\lib\ext目錄中绕德,或者由java.ext.dirs系統(tǒng)變量指定的路徑中的所有類庫(如javax.*開頭的類)患膛,開發(fā)者可以直接使用擴展類加載器。
  • 應用程序類加載器:Application ClassLoader耻蛇,該類加載器由sun.misc.Launcher$AppClassLoader來實現(xiàn)踪蹬,它負責加載用戶類路徑(ClassPath)所指定的類,開發(fā)者可以直接使用該類加載器

七. 描述一下JVM加載class文件的原理機制臣咖?

答:JVM中類的裝載是由類加載器(ClassLoader)和它的子類來實現(xiàn)的跃捣,Java中的類加載器是一個重要的Java運行時系統(tǒng)組件,它負責在運行時查找和裝入類文件中的類亡哄。 由于Java的跨平臺性枝缔,經(jīng)過編譯的Java源程序并不是一個可執(zhí)行程序,而是一個或多個類文件蚊惯。當Java程序需要使用某個類時愿卸,JVM會確保這個類已經(jīng)被加載、連接(驗證截型、準備和解析)和初始化趴荸。類的加載是指把類的.class文件中的數(shù)據(jù)讀入到內(nèi)存中,通常是創(chuàng)建一個字節(jié)數(shù)組讀入.class文件宦焦,然后產(chǎn)生與所加載類對應的Class對象发钝。加載完成后顿涣,Class對象還不完整,所以此時的類還不可用酝豪。當類被加載后就進入連接階段涛碑,這一階段包括驗證、準備(為靜態(tài)變量分配內(nèi)存并設置默認的初始值)和解析(將符號引用替換為直接引用)三個步驟孵淘。最后JVM對類進行初始化蒲障,包括:1)如果類存在直接的父類并且這個類還沒有被初始化,那么就先初始化父類瘫证;2)如果類中存在初始化語句揉阎,就依次執(zhí)行這些初始化語句。 類的加載是由類加載器完成的背捌,類加載器包括:根加載器(BootStrap)哆料、擴展加載器(Extension)摆出、系統(tǒng)加載器(System)和用戶自定義類加載器(java.lang.ClassLoader的子類)。從Java 2(JDK 1.2)開始,類加載過程采取了父親委托機制(PDM)嫉鲸。PDM更好的保證了Java平臺的安全性谷醉,在該機制中讼油,JVM自帶的Bootstrap是根加載器展蒂,其他的加載器都有且僅有一個父類加載器。類的加載首先請求父類加載器加載乖坠,父類加載器無能為力時才由其子類加載器自行加載搀突。JVM不會向Java程序提供對Bootstrap的引用。下面是關于幾個類加載器的說明:

  • Bootstrap:一般用本地代碼實現(xiàn)熊泵,負責加載JVM基礎核心類庫(rt.jar)仰迁;
  • Extension:從java.ext.dirs系統(tǒng)屬性所指定的目錄中加載類庫,它的父加載器是Bootstrap顽分;
  • System:又叫應用類加載器徐许,其父類是Extension。它是應用最廣泛的類加載器卒蘸。它從環(huán)境變量classpath或者系統(tǒng)屬性java.class.path所指定的目錄中記載類雌隅,是用戶自定義加載器的默認父加載器。

八. 描述一下JVM加載class文件的原理機制缸沃?

JVM中類的裝載是由類加載器(ClassLoader)和它的子類來實現(xiàn)的恰起,Java中的類加載器是一個重要的Java運行時系統(tǒng)組件,它負責在運行時查找和裝入類文件中的類趾牧。

由于Java的跨平臺性检盼,經(jīng)過編譯的Java源程序并不是一個可執(zhí)行程序,而是一個或多個類文件翘单。當Java程序需要使用某個類時吨枉,JVM會確保這個類已經(jīng)被加載蹦渣、連接(驗證、準備和解析)和初始化貌亭。類的加載是指把類的.class文件中的數(shù)據(jù)讀入到內(nèi)存中柬唯,通常是創(chuàng)建一個字節(jié)數(shù)組讀入.class文件,然后產(chǎn)生與所加載類對應的Class對象圃庭。加載完成后权逗,Class對象還不完整,所以此時的類還不可用冤议。當類被加載后就進入連接階段,這一階段包括驗證师坎、準備(為靜態(tài)變量分配內(nèi)存并設置默認的初始值)和解析(將符號引用替換為直接引用)三個步驟恕酸。最后JVM對類進行初始化,包括:

  • 如果類存在直接的父類并且這個類還沒有被初始化胯陋,那么就先初始化父類蕊温;
  • 如果類中存在初始化語句,就依次執(zhí)行這些初始化語句遏乔。

類的加載是由類加載器完成的义矛,類加載器包括:根加載器(BootStrap)、擴展加載器(Extension)盟萨、系統(tǒng)加載器(System)和用戶自定義類加載器(java.lang.ClassLoader的子類)凉翻。

從Java 2(JDK 1.2)開始,類加載過程采取了父親委托機制(PDM)捻激。PDM更好的保證了Java平臺的安全性制轰,在該機制中,JVM自帶的Bootstrap是根加載器胞谭,其他的加載器都有且僅有一個父類加載器垃杖。類的加載首先請求父類加載器加載,父類加載器無能為力時才由其子類加載器自行加載丈屹。JVM不會向Java程序提供對Bootstrap的引用调俘。下面是關于幾個類加載器的說明:

  • Bootstrap:一般用本地代碼實現(xiàn),負責加載JVM基礎核心類庫(rt.jar)旺垒;
  • Extension:從java.ext.dirs系統(tǒng)屬性所指定的目錄中加載類庫彩库,它的父加載器是Bootstrap;
  • System:又叫應用類加載器袖牙,其父類是Extension侧巨。它是應用最廣泛的類加載器。它從環(huán)境變量classpath或者系統(tǒng)屬性java.class.path所指定的目錄中記載類鞭达,是用戶自定義加載器的默認父加載器司忱。

九. Java對象創(chuàng)建過程

  1. JVM遇到一條新建對象的指令時首先去檢查這個指令的參數(shù)是否能在常量池中定義到一個類的符號引用皇忿。然后加載這個類(類加載過程在后邊講)
  2. 為對象分配內(nèi)存。一種辦法“指針碰撞”坦仍、一種辦法“空閑列表”鳍烁,最終常用的辦法“本地線程緩沖分配(TLAB)”
  3. 將除對象頭外的對象內(nèi)存空間初始化為0
  4. 對對象頭進行必要設置

十. 類的生命周期

類的生命周期包括這幾個部分,加載繁扎、連接幔荒、初始化、使用和卸載梳玫,其中前三部是類的加載的過程,如下圖爹梁;

  • 加載,查找并加載類的二進制數(shù)據(jù)提澎,在Java堆中也創(chuàng)建一個java.lang.Class類的對象
  • 連接姚垃,連接又包含三塊內(nèi)容:驗證、準備盼忌、初始化积糯。 1)驗證,文件格式谦纱、元數(shù)據(jù)看成、字節(jié)碼、符號引用驗證跨嘉; 2)準備川慌,為類的靜態(tài)變量分配內(nèi)存,并將其初始化為默認值偿荷; 3)解析窘游,把類中的符號引用轉(zhuǎn)換為直接引用
  • 初始化,為類的靜態(tài)變量賦予正確的初始值
  • 使用跳纳,new出對象程序中使用
  • 卸載忍饰,執(zhí)行垃圾回收

十一. Java對象結(jié)構(gòu)

Java對象由三個部分組成:對象頭、實例數(shù)據(jù)寺庄、對齊填充艾蓝。

對象頭由兩部分組成,第一部分存儲對象自身的運行時數(shù)據(jù):哈希碼斗塘、GC分代年齡赢织、鎖標識狀態(tài)、線程持有的鎖馍盟、偏向線程ID(一般占32/64 bit)于置。第二部分是指針類型,指向?qū)ο蟮念愒獢?shù)據(jù)類型(即對象代表哪個類)贞岭。如果是數(shù)組對象八毯,則對象頭中還有一部分用來記錄數(shù)組長度搓侄。

實例數(shù)據(jù)用來存儲對象真正的有效信息(包括父類繼承下來的和自己定義的)

對齊填充:JVM要求對象起始地址必須是8字節(jié)的整數(shù)倍(8字節(jié)對齊)

十二. Java對象的定位方式

句柄池、直接指針话速。

十三. 如何判斷對象可以被回收讶踪?

判斷對象是否存活一般有兩種方式:

  • 引用計數(shù):每個對象有一個引用計數(shù)屬性,新增一個引用時計數(shù)加1泊交,引用釋放時計數(shù)減1乳讥,計數(shù)為0時可以回收。此方法簡單廓俭,無法解決對象相互循環(huán)引用的問題云石。
  • 可達性分析(Reachability Analysis):從GC Roots開始向下搜索,搜索所走過的路徑稱為引用鏈研乒。當一個對象到GC Roots沒有任何引用鏈相連時留晚,則證明此對象是不可用的,不可達對象告嘲。

十四. JVM的永久代中會發(fā)生垃圾回收么?

垃圾回收不會發(fā)生在永久代奖地,如果永久代滿了或者是超過了臨界值橄唬,會觸發(fā)完全垃圾回收(Full GC)。如果你仔細查看垃圾收集器的輸出信息参歹,就會發(fā)現(xiàn)永久代也是被回收的仰楚。這就是為什么正確的永久代大小對避免Full GC是非常重要的原因。請參考下Java8:從永久代到元數(shù)據(jù)區(qū) (注:Java8中已經(jīng)移除了永久代犬庇,新加了一個叫做元數(shù)據(jù)區(qū)的native內(nèi)存區(qū))

十五. 引用的分類

  • 強引用:GC時不會被回收
  • 軟引用:描述有用但不是必須的對象僧界,在發(fā)生內(nèi)存溢出異常之前被回收
  • 弱引用:描述有用但不是必須的對象,在下一次GC時被回收
  • 虛引用(幽靈引用/幻影引用):無法通過虛引用獲得對象臭挽,用PhantomReference實現(xiàn)虛引用捂襟,虛引用用來在GC時返回一個通知。

十六. GC是什么欢峰?為什么要有GC葬荷?

答:GC是垃圾收集的意思,內(nèi)存處理是編程人員容易出現(xiàn)問題的地方纽帖,忘記或者錯誤的內(nèi)存回收會導致程序或系統(tǒng)的不穩(wěn)定甚至崩潰宠漩,Java提供的GC功能可以自動監(jiān)測對象是否超過作用域從而達到自動回收內(nèi)存的目的,Java語言沒有提供釋放已分配內(nèi)存的顯示操作方法懊直。Java程序員不用擔心內(nèi)存管理扒吁,因為垃圾收集器會自動進行管理。要請求垃圾收集室囊,可以調(diào)用下面的方法之一:System.gc() 或Runtime.getRuntime().gc() 雕崩,但JVM可以屏蔽掉顯示的垃圾回收調(diào)用魁索。 垃圾回收可以有效的防止內(nèi)存泄露,有效的使用可以使用的內(nèi)存晨逝。垃圾回收器通常是作為一個單獨的低優(yōu)先級的線程運行蛾默,不可預知的情況下對內(nèi)存堆中已經(jīng)死亡的或者長時間沒有使用的對象進行清除和回收,程序員不能實時的調(diào)用垃圾回收器對某個對象或所有對象進行垃圾回收捉貌。在Java誕生初期支鸡,垃圾回收是Java最大的亮點之一,因為服務器端的編程需要有效的防止內(nèi)存泄露問題趁窃,然而時過境遷牧挣,如今Java的垃圾回收機制已經(jīng)成為被詬病的東西。移動智能終端用戶通常覺得iOS的系統(tǒng)比Android系統(tǒng)有更好的用戶體驗醒陆,其中一個深層次的原因就在于android系統(tǒng)中垃圾回收的不可預知性瀑构。

補充:垃圾回收機制有很多種,包括:分代復制垃圾回收刨摩、標記垃圾回收寺晌、增量垃圾回收等方式。標準的Java進程既有棧又有堆澡刹。棧保存了原始型局部變量呻征,堆保存了要創(chuàng)建的對象。Java平臺對堆內(nèi)存回收和再利用的基本算法被稱為標記和清除罢浇,但是Java對其進行了改進陆赋,采用“分代式垃圾收集”。這種方法會跟Java對象的生命周期將堆內(nèi)存劃分為不同的區(qū)域嚷闭,在垃圾收集過程中攒岛,可能會將對象移動到不同區(qū)域:

  • 伊甸園(Eden):這是對象最初誕生的區(qū)域,并且對大多數(shù)對象來說胞锰,這里是它們唯一存在過的區(qū)域灾锯。
  • 幸存者樂園(Survivor):從伊甸園幸存下來的對象會被挪到這里。
  • 終身頤養(yǎng)園(Tenured):這是足夠老的幸存對象的歸宿嗅榕。年輕代收集(Minor-GC)過程是不會觸及這個地方的挠进。當年輕代收集不能把對象放進終身頤養(yǎng)園時,就會觸發(fā)一次完全收集(Major-GC)誊册,這里可能還會牽扯到壓縮领突,以便為大對象騰出足夠的空間。 與垃圾回收相關的JVM參數(shù):

-Xms / -Xmx — 堆的初始大小 / 堆的最大大小 -Xmn — 堆中年輕代的大小 -XX:-DisableExplicitGC — 讓System.gc()不產(chǎn)生任何作用 -XX:+PrintGCDetails — 打印GC的細節(jié) -XX:+PrintGCDateStamps — 打印GC操作的時間戳 -XX:NewSize / XX:MaxNewSize — 設置新生代大小/新生代最大大小 -XX:NewRatio — 可以設置老生代和新生代的比例 -XX:PrintTenuringDistribution — 設置每次新生代GC后輸出幸存者樂園中對象年齡的分布 -XX:InitialTenuringThreshold / -XX:MaxTenuringThreshold:設置老年代閥值的初始值和最大值 -XX:TargetSurvivorRatio:設置幸存區(qū)的目標使用率

十七. 判斷一個對象應該被回收

  1. 該對象沒有與GC Roots相連
  2. 該對象沒有重寫finalize()方法或finalize()已經(jīng)被執(zhí)行過則直接回收(第一次標記)案怯、否則將對象加入到F-Queue隊列中(優(yōu)先級很低的隊列)在這里finalize()方法被執(zhí)行君旦,之后進行第二次標記,如果對象仍然應該被GC則GC,否則移除隊列金砍。 (在finalize方法中局蚀,對象很可能和其他 GC Roots中的某一個對象建立了關聯(lián),finalize方法只會被調(diào)用一次恕稠,且不推薦使用finalize方法)

十八. 回收方法區(qū)

方法區(qū)回收價值很低琅绅,主要回收廢棄的常量和無用的類。

如何判斷無用的類:

  1. 該類所有實例都被回收(Java堆中沒有該類的對象)
  2. 加載該類的ClassLoader已經(jīng)被回收
  3. 該類對應的java.lang.Class對象沒有在任何地方被引用鹅巍,無法在任何地方利用反射訪問該類

十九. 垃圾收集算法

GC最基礎的算法有三種: 標記 -清除算法千扶、復制算法、標記-壓縮算法骆捧,我們常用的垃圾回收器一般都采用分代收集算法澎羞。

  • 標記 -清除算法,“標記-清除”(Mark-Sweep)算法敛苇,如它的名字一樣妆绞,算法分為“標記”和“清除”兩個階段:首先標記出所有需要回收的對象,在標記完成后統(tǒng)一回收掉所有被標記的對象枫攀。
  • 復制算法括饶,“復制”(Copying)的收集算法,它將可用內(nèi)存按容量劃分為大小相等的兩塊来涨,每次只使用其中的一塊巷帝。當這一塊的內(nèi)存用完了,就將還存活著的對象復制到另外一塊上面扫夜,然后再把已使用過的內(nèi)存空間一次清理掉。
  • 標記-壓縮算法驰徊,標記過程仍然與“標記-清除”算法一樣笤闯,但后續(xù)步驟不是直接對可回收對象進行清理,而是讓所有存活的對象都向一端移動棍厂,然后直接清理掉端邊界以外的內(nèi)存
  • 分代收集算法颗味,“分代收集”(Generational Collection)算法,把Java堆分為新生代和老年代牺弹,這樣就可以根據(jù)各個年代的特點采用最適當?shù)氖占惴ā?/li>

二十. 垃圾回收器

  • Serial收集器浦马,串行收集器是最古老,最穩(wěn)定以及效率高的收集器张漂,可能會產(chǎn)生較長的停頓晶默,只使用一個線程去回收。
  • ParNew收集器航攒,ParNew收集器其實就是Serial收集器的多線程版本磺陡。
  • Parallel收集器,Parallel Scavenge收集器類似ParNew收集器,Parallel收集器更關注系統(tǒng)的吞吐量币他。
  • Parallel Old 收集器坞靶,Parallel Old是Parallel Scavenge收集器的老年代版本,使用多線程和“標記-整理”算法
  • CMS收集器蝴悉,CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標的收集器彰阴。
  • G1收集器,G1 (Garbage-First)是一款面向服務器的垃圾收集器,主要針對配備多顆處理器及大容量內(nèi)存的機器. 以極高概率滿足GC停頓時間要求的同時,還具備高吞吐量性能特征

二十一. GC日志分析

摘錄GC日志一部分(前部分為年輕代gc回收拍冠;后部分為full gc回收):

2016-07-05T10:43:18.093+0800: 25.395: [GC [PSYoungGen: 274931K->10738K(274944K)] 371093K->147186K(450048K), 0.0668480 secs] [Times: user=0.17 sys=0.08, real=0.07 secs] 
2016-07-05T10:43:18.160+0800: 25.462: [Full GC [PSYoungGen: 10738K->0K(274944K)] [ParOldGen: 136447K->140379K(302592K)] 147186K->140379K(577536K) [PSPermGen: 85411K->85376K(171008K)], 0.6763541 secs] [Times: user=1.75 sys=0.02, real=0.68 secs]

通過上面日志分析得出尿这,PSYoungGen、ParOldGen倦微、PSPermGen屬于Parallel收集器妻味。其中PSYoungGen表示gc回收前后年輕代的內(nèi)存變化;ParOldGen表示gc回收前后老年代的內(nèi)存變化欣福;PSPermGen表示gc回收前后永久區(qū)的內(nèi)存變化责球。young gc 主要是針對年輕代進行內(nèi)存回收比較頻繁,耗時短拓劝;full gc 會對整個堆內(nèi)存進行回城雏逾,耗時長,因此一般盡量減少full gc的次數(shù)

二十二. 調(diào)優(yōu)命令

Sun JDK監(jiān)控和故障處理命令有jps jstat jmap jhat jstack jinfo

  • jps郑临,JVM Process Status Tool,顯示指定系統(tǒng)內(nèi)所有的HotSpot虛擬機進程栖博。
  • jstat,JVM statistics Monitoring是用于監(jiān)視虛擬機運行時狀態(tài)信息的命令厢洞,它可以顯示出虛擬機進程中的類裝載仇让、內(nèi)存、垃圾收集躺翻、JIT編譯等運行數(shù)據(jù)丧叽。
  • jmap,JVM Memory Map命令用于生成heap dump文件
  • jhat公你,JVM Heap Analysis Tool命令是與jmap搭配使用踊淳,用來分析jmap生成的dump,jhat內(nèi)置了一個微型的HTTP/HTML服務器陕靠,生成dump的分析結(jié)果后迂尝,可以在瀏覽器中查看
  • jstack,用于生成java虛擬機當前時刻的線程快照剪芥。
  • jinfo垄开,JVM Configuration info 這個命令作用是實時查看和調(diào)整虛擬機運行參數(shù)。

二十三. 調(diào)優(yōu)工具

常用調(diào)優(yōu)工具分為兩類,jdk自帶監(jiān)控工具:jconsole和jvisualvm税肪,第三方有:MAT(Memory Analyzer Tool)说榆、GChisto虚吟。

  • jconsole,Java Monitoring and Management Console是從java5開始签财,在JDK中自帶的java監(jiān)控和管理控制臺串慰,用于對JVM中內(nèi)存,線程和類等的監(jiān)控
  • jvisualvm唱蒸,jdk自帶全能工具邦鲫,可以分析內(nèi)存快照、線程快照神汹;監(jiān)控內(nèi)存變化庆捺、GC變化等。
  • MAT屁魏,Memory Analyzer Tool滔以,一個基于Eclipse的內(nèi)存分析工具,是一個快速氓拼、功能豐富的Java heap分析工具你画,它可以幫助我們查找內(nèi)存泄漏和減少內(nèi)存消耗
  • GChisto,一款專業(yè)分析gc日志的工具

二十四. Minor GC與Full GC分別在什么時候發(fā)生桃漾?

新生代內(nèi)存不夠用時候發(fā)生MGC也叫YGC坏匪,JVM內(nèi)存不夠的時候發(fā)生FGC

二十五. 你知道哪些JVM性能調(diào)優(yōu)

  • 設定堆內(nèi)存大小

    • -Xmx:堆內(nèi)存最大限制。
  • 設定新生代大小撬统。 新生代不宜太小适滓,否則會有大量對象涌入老年代

    • -XX:NewSize:新生代大小
    • -XX:NewRatio 新生代和老生代占比
    • -XX:SurvivorRatio:伊甸園空間和幸存者空間的占比
  • 設定垃圾回收器 年輕代用 -XX:+UseParNewGC 年老代用-XX:+UseConcMarkSweepGC

寫在最后

想進BAT,只會JVM可不行喲恋追,像Kafka凭迹、Mysql、Tomcat苦囱、Docker嗅绸、Spring、MyBatis沿彭、Nginx、Netty喉刘、Dubbo、Redis漆弄、Netty睦裳、Spring cloud、分布式撼唾、高并發(fā)廉邑、性能調(diào)優(yōu)、微服務等架構(gòu)技術(shù)都要掌握!

針對以上技術(shù)點蛛蒙,筆者已經(jīng)準備了一份完整的面試題PDF糙箍,而且基本上都是帶答案的,今年底或明年初想跳槽漲薪的朋友可以看下牵祟!點擊下方傳送門即可免費領壬詈弧!

傳送門

以下是部分面試題截圖

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末诺苹,一起剝皮案震驚了整個濱河市咕晋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌收奔,老刑警劉巖掌呜,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異坪哄,居然都是意外死亡质蕉,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門损姜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來饰剥,“玉大人,你說我怎么就攤上這事摧阅√兀” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵棒卷,是天一觀的道長顾孽。 經(jīng)常有香客問我,道長比规,這世上最難降的妖魔是什么若厚? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮蜒什,結(jié)果婚禮上测秸,老公的妹妹穿的比我還像新娘。我一直安慰自己灾常,他們只是感情好霎冯,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著钞瀑,像睡著了一般沈撞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上雕什,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天缠俺,我揣著相機與錄音显晶,去河邊找鬼。 笑死壹士,一個胖子當著我的面吹牛磷雇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播墓卦,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼倦春,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了落剪?” 一聲冷哼從身側(cè)響起睁本,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎忠怖,沒想到半個月后呢堰,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡凡泣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年枉疼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鞋拟。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡骂维,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出贺纲,到底是詐尸還是另有隱情航闺,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布猴誊,位于F島的核電站潦刃,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏懈叹。R本人自食惡果不足惜乖杠,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望澄成。 院中可真熱鬧胧洒,春花似錦、人聲如沸墨状。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽歉胶。三九已至汛兜,卻和暖如春巴粪,著一層夾襖步出監(jiān)牢的瞬間通今,已是汗流浹背粥谬。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留辫塌,地道東北人漏策。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像臼氨,于是被迫代替她去往敵國和親掺喻。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 介紹JVM中7個區(qū)域储矩,然后把每個區(qū)域可能造成內(nèi)存的溢出的情況說明 程序計數(shù)器:看做當前線程所執(zhí)行的字節(jié)碼行號指示器...
    jemmm閱讀 2,229評論 0 9
  • 這篇文章是我之前翻閱了不少的書籍以及從網(wǎng)絡上收集的一些資料的整理感耙,因此不免有一些不準確的地方,同時不同JDK版本的...
    高廣超閱讀 15,601評論 3 83
  • 1持隧、面向?qū)ο蟮奶卣饔心男┓矫? 答:面向?qū)ο蟮奶卣髦饕幸韵聨讉€方面: 1)抽象:抽象是將一類對象的共同特征總結(jié)出...
    yshenhn閱讀 1,159評論 0 8
  • 1.JVM的內(nèi)存結(jié)構(gòu)和管理機制即硼; JVM實例:一個獨立運行的java程序,是進程級別 JVM執(zhí)行引擎:用戶運行程序...
    愚人9袋閱讀 1,636評論 0 1
  • 紅色和藍色在一起剛好互補屡拨,紅色做事粗心只酥,但性格開放活潑,藍色心思細膩呀狼、在細節(jié)方面處理的很好裂允,彌補的剛好,工作中...
    孫萬笑SWX閱讀 331評論 0 0