JVM 面試 詳解

1.ClassLoader相關

1. 什麼是類加載器?
讀取 Java 字節代碼,並轉換成java.lang.Class類的一個實例。

2. 類相同的判斷?
被相同的類加載加載的類纔是相同的類,這裏指的“相同”,包括類的Class對象的equals()方法、isAssignableFrom()方法、isInstance()方法、instanceof關鍵字等判斷出來的結果。

3. 類加載器種類?

  • Bootstrap ClassLoader,加載$JAVA_HOME/jre/rt.jar
  • Extension ClassLoader,加載JAVA_HOME/jre/ext/*.jar
  • Application ClassLoader,加載ClassPath的jar

實例代碼

public static void main(String[] args) {
		// BootStrapClassLoader: Object是rt.jar中的,這個是c實現的,所以是null
		System.err.println(Object.class.getClassLoader());
		// AppClassLoader: sun.misc.Launcher$AppClassLoader@73d16e93
		System.err.println(MyObject.class.getClassLoader());
		// ExtClassLoader :sun.misc.Launcher$ExtClassLoader@15db9742
		System.err.println(MyObject.class.getClassLoader().getParent());
		// ExtClassLoader的父親是BootStrapClassLoader 打印爲null
		System.err.println(MyObject.class.getClassLoader().getParent().getParent());
	}

4. 雙親委派模型?
類加載時,首先優先父類加載,父類加載不了就交給子類,子類加載不了就拋出NotFondClassException。

雙親委派模型優點:
由於bootstrapclassloader已經加載了java.lang.String了,所以直接就按照了jdk中的java.lang.String來了,裏面是沒有main函數的,避免了java的核心API被篡改,還避免了類重複加載。在這裏插入圖片描述

5. 能否在java程序運行時,動態對類的字節碼進行修改?(比如加個方法耗時時間,參數統計)
java探針技術,詳情見我們另一篇博客:java探針技術實操 之 java運行時修改類

6.自定義類加載器怎麼實現包隔離?
見我另一篇博客實操:自定義類加載器實現不同版本jar共存

2.jvm運行時內存相關

1.java8 JVM運行時內存區域圖在這裏插入圖片描述
程序計數器 : 線程私有,維護線程執行情況(比如:線程切換回來時知道從哪開始執行)。

本地方法棧: 線程私有,服務於native方法。

虛擬機棧: 當線程執行一個方法時,會創建一個對應的棧幀,並將其壓棧,當方法執行完畢之後,便會將棧幀出棧。線程結束就回收棧空間。裏面存儲下面四個東西:
1)、局部變量表
八種基本類型(int,long等)的值,對象的變量名(引用變量)
2)、操作數棧
存儲程序中的所有計算過程
3)、指向運行時常量池的引用
4)、方法返回地址

本地內存: 也就是你機器的內存。

方法區(元空間): 線程共享,存儲類的元信息,常量、靜態變量,java7是存儲在堆裏面的,java8將其移出來到本地內存裏面了。

直接內存: NIO的Buffer提供了一個可以不經過JVM內存直接訪問系統物理內存的類——DirectBuffer

: new出來的對象存儲區域,詳解見下。

3.堆詳解

在這裏插入圖片描述
當對象new出來,先放到Eden區(伊甸園區)。第一次垃圾回收時,將存活的對象複製到from區,Eden區清空。當from區也滿了,將存活的對象複製到to區,並清空from區,對象年齡加1,並且from和to交換角色,也就是每次垃圾回收時,to區必須是空的,當對象的年齡達到一個閾值(默認值爲15)還存活,就移動到老年代。

堆相關參數:
-Xms4g : 初始的Heap的大小(新生代和老年代)。
-Xmx4g:最大Heap的大小。必須設置 -Xms 和 -Xmx的值爲一樣,因爲當Heap不夠用時,會發生內存抖動,影響程序運行穩定性。
-Xss512k :設置每個線程的堆棧大小,理論上越大,系統能開的線程越多,但是操作系統對一個進程內的線程數還是有限制的,不能無限生成。
-XX:NewRatio=4:設置年輕代(包括Eden和兩個Survivor(from和to)區)與年老代的比值
-XX:SurvivorRatio=8:設置年輕代中Eden區與Survivor區(from和to)的大小比值。
-XX:MaxTenuringThreshold=15:設置垃圾最大年齡。

區域概括
① 新生代(Young Generation):大多數對象在新生代中被創建,其中很多對象的生命週期很短。每次新生代的垃圾回收(又稱Minor GC)後只有少量對象存活,所以選用複製算法,只需要少量的複製成本就可以完成回收。

新生代內又分三個區:一個Eden區,兩個Survivor區(一般而言),大部分對象在Eden區中生成。當Eden區滿時,還存活的對象將被複制到兩個Survivor區(中的一個)。當這個Survivor區滿時,此區的存活且不滿足“晉升”條件的對象將被複制到另外一個Survivor區。對象每經歷一次Minor GC,年齡加1,達到“晉升年齡閾值”後,被放到老年代,這個過程也稱爲“晉升”。顯然,“晉升年齡閾值”的大小直接影響着對象在新生代中的停留時間,在Serial和ParNew GC兩種回收器中,“晉升年齡閾值”通過參數MaxTenuringThreshold設定,默認值爲15。

② 老年代(Old Generation):在新生代中經歷了N次垃圾回收後仍然存活的對象,就會被放到年老代,該區域中對象存活率高。老年代的垃圾回收(又稱Major GC)通常使用“標記-清理”或“標記-整理”算法。整堆包括新生代和老年代的垃圾回收稱爲Full GC(HotSpot VM裏,除了CMS之外,其它能收集老年代的GC都會同時收集整個GC堆,包括新生代)。

③ 永久代(Perm Generation):主要存放元數據,例如Class、Method的元信息,與垃圾回收要回收的Java對象關係不大。相對於新生代和年老代來說,該區域的劃分對垃圾回收影響比較小。

GC種類
1.Minor GC: 叫YongGC或GC或輕GC, 對新生代區域的GC,非常頻繁,回收速度快。
2.Full GC : 全局GC,對整個新生代、老生代、元空間的全局範圍的GC;

GC日誌
打印gc日誌參數,GC日誌既可以直接在命令行輸出,也可生成到指定的日誌文件中

-XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:/home/logs/gc.log
public class OrderService {
	static class Phone {
		byte[] money = new byte[1024];
		String name = "i am a phone";
	}

	public static void main(String[] args) throws InterruptedException {

		List<Phone> phones = new ArrayList<OrderService.Phone>();
		while (true) {
			phones.add(new Phone());
			Thread.sleep(1);
		}
	}
}

設置運行參數:-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:NewRatio=1
堆大小:10M
年輕代與老年代的比例約爲 1:1

執行結果:

[GC (Allocation Failure) [PSYoungGen: 4096K->480K(4608K)] 4096K->4008K(9728K), 0.0013970 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 480K->0K(4608K)] [ParOldGen: 3528K->3848K(5120K)] 4008K->3848K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0067804 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->3064K(4608K)] [ParOldGen: 3848K->4807K(5120K)] 7944K->7872K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0088351 secs] [Times: user=0.11 sys=0.00, real=0.01 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->4038K(4608K)] [ParOldGen: 4807K->4807K(5120K)] 8903K->8846K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0055923 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->4095K(4608K)] [ParOldGen: 4807K->4807K(5120K)] 8903K->8903K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0048371 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 4825K->4825K(5120K)] 8921K->8921K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0047980 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 4842K->4842K(5120K)] 8938K->8938K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0048467 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 4859K->4859K(5120K)] 8955K->8955K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0047925 secs] [Times: user=0.11 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 4876K->4876K(5120K)] 8972K->8972K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0086871 secs] [Times: user=0.11 sys=0.00, real=0.01 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 4893K->4893K(5120K)] 8989K->8989K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0047263 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 4910K->4910K(5120K)] 9006K->9006K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0048743 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 4927K->4927K(5120K)] 9023K->9023K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0047919 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 4944K->4944K(5120K)] 9040K->9040K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0047698 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 4961K->4961K(5120K)] 9057K->9057K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0047385 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 4978K->4978K(5120K)] 9074K->9074K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0050405 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 4995K->4995K(5120K)] 9091K->9091K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0048963 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 5012K->5012K(5120K)] 9108K->9108K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0048850 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 5029K->5029K(5120K)] 9125K->9125K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0051970 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 5046K->5046K(5120K)] 9142K->9142K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0050820 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 5063K->5063K(5120K)] 9159K->9159K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0048128 secs] [Times: user=0.09 sys=0.00, real=0.01 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 5080K->5080K(5120K)] 9176K->9176K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0051470 secs] [Times: user=0.11 sys=0.00, real=0.01 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 5097K->5097K(5120K)] 9193K->9193K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0047988 secs] [Times: user=0.11 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 5114K->5114K(5120K)] 9210K->9210K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0050377 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 5119K->5119K(5120K)] 9215K->9215K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0051825 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 5119K->5119K(5120K)] 9215K->9215K(9728K), [Metaspace: 2618K->2618K(1056768K)], 0.0049117 secs] [Times: user=0.11 sys=0.00, real=0.01 secs] 
[Full GC (Ergonomics) [PSYoungGen: 4096K->0K(4608K)] [ParOldGen: 5119K->502K(5120K)] 9215K->502K(9728K), [Metaspace: 2619K->2619K(1056768K)], 0.0046179 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
Exception in thread "main" Heap
 PSYoungGen      total 4608K, used 108K [0x00000000ffb00000, 0x0000000100000000, 0x0000000100000000)
  eden space 4096K, 2% used [0x00000000ffb00000,0x00000000ffb1b068,0x00000000fff00000)
  from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
  to   space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
 ParOldGen       total 5120K, used 502K [0x00000000ff600000, 0x00000000ffb00000, 0x00000000ffb00000)
  object space 5120K, 9% used [0x00000000ff600000,0x00000000ff67dba0,0x00000000ffb00000)
 Metaspace       used 2651K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 283K, capacity 386K, committed 512K, reserved 1048576K
java.lang.OutOfMemoryError: Java heap space
	at jvm.OrderService$Phone.<init>(OrderService.java:9)
	at jvm.OrderService.main(OrderService.java:17)

解釋:
1.YongGC

[GC (Allocation Failure) [PSYoungGen: 4096K->480K(4608K)] 4096K->4008K(9728K), 0.0013970 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
  1. GC : 表示是一次YGC(Young GC)。
  2. Allocation Failure : 表示失敗的類型。年輕代中沒有足夠區域能夠存放需要分配的數據而失敗
  3. PSYoungGen : 表示年輕代情況。
  4. 4096K->480K : 回收前年輕代佔用4096K,回收後佔用480K(都移到老年代了)。
  5. 4608K : 年輕代大小(上面設置了比例爲1:1,整堆大小約10M, 一半剛好差不多是4608)。
  6. 4096K->4008K : 整個堆佔用從4096K降爲4008K,壓根沒怎麼回收。
  7. 9728K :整個堆的大小。
  8. 0.0013970 secs : GC用的總時間。
  9. [Times: user=0.00 sys=0.00, real=0.00 secs] : 分別表示,用戶態佔用時長,內核用時,真實用時。

2.FullGC

[Full GC (Ergonomics) [PSYoungGen: 4096K->0K(4608K)] [ParOldGen: 5119K->502K(5120K)] 9215K->502K(9728K), [Metaspace: 2619K->2619K(1056768K)], 0.0046179 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 

  1. Full GC : 表示是一次Full GC。
  2. [PSYoungGen: 4096K->0K(4608K)] :年輕代:垃圾收集前->垃圾收集後(年輕代堆總大小)
  3. [ParOldGen: 5119K->502K(5120K)] : 老年代:垃圾收集前->垃圾收集後(年老代堆總大小)
  4. 9215K->502K(9728K) : 垃圾收集前->垃圾收集後(總堆大小)
  5. [Metaspace: 2619K->2619K(1056768K)] : Metaspace空間信息,垃圾收集前->垃圾收集後(總元空間大小)

3.面試題

1.老年代和新生代的比例
默認的,新生代 ( Young ) 與老年代 ( Old ) 的比例的值爲 1:2 ( 該值可以通過參數 –XX:NewRatio 來指定 ),即:新生代 ( Young ) = 1/3 的堆空間大小。老年代 ( Old ) = 2/3 的堆空間大小。

2.YGC和FGC發生的具體場景
YGC: 新生代(eden區)不足,執行 young gc
FGC: old空間不足,perm空間不足,調用方法System.gc() ,ygc時的悲觀策略, dump live的內存信息時(jmap –dump:live),都會執行full gc。

3.GC回收算法?
標記-清除法: 標記出沒有用的對象,然後一個一個回收掉。
缺點:標記和清除兩個過程效率不高,產生內存碎片導致需要分配較大對象時無法找到足夠的連續內存而需要觸發一次GC操作。

複製算法: 按照容量劃分二個大小相等的內存區域,當一塊用完的時候將活着的對象複製到另一塊上,然後再把已使用的內存空間一次清理掉。
缺點:將內存縮小爲了原來的一半。

標記-整理法:標記出沒有用的對象,讓所有存活的對象都向一端移動,然後直接清除掉端邊界以外的內。
優點:解決了標記- 清除算法導致的內存碎片問題和在存活率較高時複製算法效率低的問題。

分代回收: 根據對象存活週期的不同將內存劃分爲幾塊,一般是新生代和老年代,新生代基本採用複製算法,老年代採用標記整理算法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章