大綱
- 虛擬機堆疊和本地方法堆疊的區別?
- 垃圾回收演算法知道哪些,CMS 說一下,并發標記階段處理速度慢的原因可能是什么,怎么進行優化?
- java虛擬機有哪些磁區?
- 請簡單描述一下類的加載程序?
- 還有CMS采用哪種回收演算法?使用CMS怎樣解決記憶體碎片的問題呢?
- 如何判斷物件已死?
- 介紹一下參考?
- 發生Young GC的時候需要掃描老年代的物件嗎?
虛擬機堆疊和本地方法堆疊的區別?
簡單的來說,虛擬機堆疊是為虛擬機執行位元組碼指令(java方法)服務,而本地方法堆疊是為了虛擬機執行本地native方法而服務,
垃圾回收演算法知道哪些,CMS 說一下,并發標記階段處理速度慢的原因可能是什么,怎么進行優化?
垃圾回收演算法分別有:標記-清除法、標記-復制法和標記-整理法
-
標記-清除法:第一步先標記出所有要回收的物件(存活的物件),第二步回收所有被標記(未被標記)的物件,
缺點:
- 會隨著物件的增多而導致標記和清除所用的時間也線性增多,
- 會在記憶體中產生大量的不連續的記憶體碎片
-
標記-復制法:此演算法解決了標記-清除法在有大量可回收物件的情況下效率低的問題,它把記憶體一分為二,然后平時先使用其中的一半,在進行回收的時候,把存活的物件移動到另一半還沒使用的記憶體中,然后直接清理掉之前那半記憶體(要回收物件存在的記憶體區域),
缺點:顯而易見,把可用記憶體縮小為原來的一半,存在較大的空間浪費,
-
標記-整理法:先把所有存活物件移動到一端,然后把邊界以外的記憶體都清理掉,
缺點:對于存活物件很多的老年代,會導致過多的物件移動,
CMS收集器是一種追求最短回收停頓時間的收集器,它的作業大致分為下面四個步驟
- 初始標記:單獨的垃圾回收執行緒標記所有的GC Roots能直接關聯的物件,,速度很快
- 并發標記:遍歷整個物件圖進行標記,垃圾回收執行緒與用戶執行緒并發,不需要停頓用戶執行緒
- 重新標記:并發標記是用戶執行緒可能導致標記產生變動,所以需要重新調整
- 并發清理:回收垃圾,不停頓用戶執行緒
并發階段處理慢的可能原有是,因為用戶執行緒和垃圾回收執行緒并發執行,有可能存在執行緒背景關系切換等帶來的性能消耗,如果要提高垃圾回收的速度,可能要停掉部分的用戶執行緒,
java虛擬機有哪些磁區?
如下圖

請簡單描述一下類的加載程序?

-
加載:在加載階段,JVM通過一個類的全限定名稱來獲取二進制位元組流,最后在記憶體里生成一個代表該類的Class物件,加載階段是程式員最能掌控的一個階段,因為并沒有限定要通過何種途徑來獲取二進制流,所以我們可以通過自定義的類加載器,通過網路位元組流傳輸等多種途徑去獲取二進制流,
-
**驗證:**加載與連接是交叉進行的,比如某些驗證位元組碼檔案格式的操作,驗證階段主要是確保Class檔案里面的資訊符合規范,不會影響到虛擬機自身的安全
-
**準備:**這個階段主要為類變數(靜態變數)分配記憶體并初始化賦值,注意,這些類變數使用的記憶體在方法取,而方法區只是一個邏輯上的說法,在jdk7的方法區表現為永久代,而在jdk8使用了元空間的概念,所以類變數是隨著Class物件放在堆里面,
public static int a = 199; //在準備階段,賦給a的初始值是0而不是199 //只有當存放在<clinit>()的putstatic指令被執行后才會被賦值為199,而<clinit>類構造方法被執行是在初始化階段才被執行 public static final int b = 199; //而類變數b是由final修飾的,所以它的值199被存放于ConstantValue屬性(被其對應的欄位表參考)中,而ConstantValue會指向它對應的常量池之中的字面量,所以在準備階段就直接對b賦值 -
決議:決議階段就是把符號參考轉換為直接參考,符號就是用任意的字面量來描述參考的目標,而直接參考是可以直接指向目標的指標、相對偏移量或者是能間接定位到目標的句柄,直接參考直接對應著虛擬機的真實記憶體布局,符號參考就是class檔案常量池中的CONSTANT_Class_info、CONSTANT_Field_info、CONSTANT_Method_info等常量,
-
初始化:初始化階段就是執行類構造器()的程序,而()是javac編譯是自動生成的,它搜集了類中對類變數賦值的動作和static{}靜態代碼塊的陳述句,如果一個普通的類沒有靜態變數賦值動作也沒有靜態代碼塊,()是不存在的,java虛擬機會保證在子類的()方法執行前先執行父類的()方法,而無需顯式呼叫,
還有CMS采用哪種回收演算法?使用CMS怎樣解決記憶體碎片的問題呢?
CMS在并發清理階段是基于標記-清除演算法,如果空間導致空間碎片過多,導致無法找到足夠大的記憶體來分配物件,就會提前觸發Full GC (同時清理年輕代和永久代)進行碎片整理,
如何判斷物件已死?
- 參考計數法:如果一個物件被參考,那么它的參考計數器則加一,取消參考則減一;若一個物件的參考計數器值為0,則物件已死,但參考計數器無法解決物件相互相互參考的問題,因為這樣導致它們的參考計數器都不為1,所以不能進行垃圾回收(垃圾參考垃圾居然變成不是垃圾)
- 可達性分析:主流的java虛擬機都通過這種方法進行分析,這個方法主要通過一系列的GC Root,而GC Root分別參考了不同物件,而那些物件又有可能參考了別的物件,從而這些物件一起形成了圖,如果某一物件不在這個圖里,換句話說這個物件對于GC Root來說是不可達的,就可以判定物件是垃圾,固定的GC Root可以為一下幾種:
- 虛擬機堆疊參考的物件
- 方法區中靜態屬性參考的物件
- 方法區中常量參考的物件
- java虛擬機內部的參考,例如Class物件、例外物件等
- 被同步鎖(synchronized)持有的物件
介紹一下參考?
-
強參考
類似于 Object obj = new Object()的參考,java虛擬機永遠不會回收被強參考的物件,
-
軟參考
被軟參考的物件會在記憶體溢位之前,被回收,
String str = new String("abc"); SoftReference<String> softReference = new SoftReference<>(str); -
弱參考
被弱參考的物件會在垃圾回收發生時被回收,而不管記憶體是否足夠,
String str = new String("abc"); WeakReference<String> weakReference = new WeakReference<>(str); str = null; System.gc(); System.out.println(weakReference.get()); //null -
虛參考
虛參考的作用僅僅是物件被回收時收到一個系統的通知,不能通過虛參考來獲取實體,虛參考一定要配合參考佇列使用,在虛參考的物件被回收時,虛擬機會將參考放入參考佇列,這相當于一種系統通知,
String str2 = new String("哈哈哈哈");
ReferenceQueue<String> stringReferenceQueue = new ReferenceQueue<>();
PhantomReference<String> phantomReference = new PhantomReference<>(str2,stringReferenceQueue);
str2 = null;
System.gc();
//強制執行所有失去參考的物件的finalize()方法
System.runFinalization();
System.out.println(stringReferenceQueue.poll() == phantomReference);
//true
發生Young GC的時候需要掃描老年代的物件嗎?
不需要,為了解決存在跨代參考時把整個老年代都加進GC Roots掃描范圍,垃圾收集器在新生代建立了名為記憶集的資料結構,這個記憶集通常用卡表的方式去實作,卡表其實是一個位元組陣列(CARD_TABLE),而每一個元素都對應標識了一個記憶體塊,這個記憶體塊叫做卡頁,每一個卡頁中儲存著多個物件,如果卡頁中有物件存在跨代參考,則把卡表陣列對應的元素的值標記為1,則在下次掃描中就能輕易得出哪些卡頁中包含跨代指標,則把這些物件一并加入到GC Roots中一起掃描,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/353372.html
標籤:java
上一篇:LeetCode 71~75
下一篇:感恩CSDN,感謝有你
