天天看點

GC相關面試題

GC相關面試題

文章目錄

  • ​​GC相關面試題​​
  • ​​Object的finalize()方法的作用是否與C++的析構函數作用相同?​​
  • ​​為什麼不能顯示直接調用finalize方法?​​
  • ​​Java中的強引用,軟引用,弱引用,虛引用有什麼用?​​
  • ​​GC是在什麼時候,對什麼東西,做了什麼事情?​​
  • ​​Java虛拟機規範将JVM虛拟機所管理的記憶體分為幾部分?​​
  • ​​有哪些方法可以判斷一個對象已經可以被回收,JVM怎麼判斷一個對象已經消亡可以被回收?​​
  • ​​哪些對象可以作為GC Roots?​​

Object的finalize()方法的作用是否與C++的析構函數作用相同?

與C++的析構函數不同,析構函數确定調用,而它是不确定的

當垃圾回收器宣告一個對象死亡時,至少要經過兩次的标記過程,如果對象在可達性分析夠發現對象沒有與GCRoot連接配接的引用鍊,就會被第一次标記。并且判斷是否執行finalized()方法,如果對象覆寫finzlize方法并且未被應用過這個對象就會被放置在F-Queue隊列中。并在稍後有一個虛拟機建立的一個低優先級的finalize去執行觸發finalize方法。由于優先級太低,方法執行随時可能被中止。

finalize方法的作用是為對象提供最後一次逃脫死亡的機會。

由于finalize方法的運作不确定性較大,無法保證各對象的調用順序。同時運作代價十分高昂,是以不建議使用。

為什麼不能顯示直接調用finalize方法?

finalize方法在垃圾回收時一定會被執行,而如果在此之前顯示執行的話,也就是說finalize會被執行兩次以上,而在第一次資源已經被釋放,那麼在第二次釋放資源時系統一定會報錯,是以一般finalize方法的通路權限和父類保持一緻,為protected。

Java中的強引用,軟引用,弱引用,虛引用有什麼用?

強引用(Strong Reference):

  1. 最普遍的引用:Object obj = new Object();
  2. 當對象為強引用時,并且記憶體不足時,Java甯可抛出OOM異常也不會回收具有強引用的對象。
  3. 如果我們不實用這個對象了,我們可以通過将對象設定為Null來弱化引用,使其被回收。或者等待超出它的生命周期範圍。這時GC就會認為不存在該對象的引用,就會将其回收。

軟引用(Soft Reference):

  1. 對象處于有用但非必須狀态
  2. 隻有當記憶體空間不足時,GC會回收該引用的對象的記憶體
  3. 可以用軟引用來實作高速緩存
  4. ​String str = new String("abc"); // 強引用​

    ​​

    ​SoftReference<String> softref = new SoftReference<String>(str); // 軟引用​

弱引用(Weak Reference):

  1. 非必須的對象,比弱引用更弱一些
  2. GC時會被回收
  3. 被回收的機率也不大,因為GC的線程優先級比較低
  4. 适用于引用偶爾被使用且不影響垃圾收集機制的對象
  5. ​String str = new String("abc"); // 強引用​

    ​​

    ​WeakReference<String> weakref = new WeakReference<String>(str); // 軟引用​

虛引用(PhantomReference):

  1. 不會決定對象的生命周期
  2. 任何時候都可能被垃圾回收器回收
  3. 跟蹤對象被垃圾收集器回收的活動,其哨兵作用
  4. 必須和應用隊列ReferenceQueue聯合使用
String str = new String("abc");
RegerenceQueue queue = new RegerenceQueue();
PhantomReference ref = new PhantomReference(str,queue);      
GC相關面試題

GC是在什麼時候,對什麼東西,做了什麼事情?

什麼時候

  1. 系統自身決定,不可預測的時間/調用System.gc()的時候。
  2. 新生代、老年代結構,提出minor gc/full gc
  3. 說明minor gc/full gc的觸發條件、OOM的觸發條件,降低GC的調優的政策。
  4. eden滿了minor gc,升到老年代的對象大于老年代剩餘空間full gc,或者小于時被HandlePromotionFailure參數強制full gc;gc與非gc時間耗時超過了GCTimeRatio的限制引發OOM,調優諸如通過NewRatio控制新生代老年代比例,通過 MaxTenuringThreshold控制進入老年前生存次數等

總結:程式員不能具體控制時間,系統在不可預測的時間調用System.gc()函數的時候;當然可以通過調優,用NewRatio控制newObject和oldObject的比例,用MaxTenuringThreshold 控制進入oldObject的次數,使得oldObject 存儲空間延遲達到full gc,進而使得計時器引發gc時間延遲OOM的時間延遲,以延長對象生存期。

對什麼東西?

  1. 從gc root開始搜尋,搜尋不到的對象
  2. 從root搜尋不到,而且經過第一次标記、清理後,仍然沒有複活的對象

總結:超出了作用域或引用計數為空的對象;從gc root開始搜尋找不到的對象,而且經過一次标記、清理,仍然沒有複活的對象。

做什麼?

  1. 删除不使用的對象,騰出記憶體空間。
  2. 停止其他線程執行、運作finalize等
  3. 新生代做的是複制清理、from survivor、to survivor是幹啥用的、老年代做的是标記清理、标記清理後碎片要不要整理、複制清理和标記清理有有什麼優劣勢
  4. 清楚串行、并行(整理/不整理碎片)、CMS等搜集器可作用的年代、特點、優劣勢,并且能說明控制/調整收集器選擇的方式。

總結:删除不使用的對象,回收記憶體空間;運作預設的finalize,當然程式員想立刻調用就用dipose調用以釋放資源如檔案句柄,JVM用from survivor、to survivor對它進行标記清理,對象序列化後也可以使它複活。

Java虛拟機規範将JVM虛拟機所管理的記憶體分為幾部分?

GC相關面試題
  1. 程式計數器(Program Counter Register)

是一塊較小的記憶體空間,它的作用可以看做是目前線程所執行位元組碼的行号訓示器。是線程私有,生命周期與線程相同。

  1. Java虛拟機棧(Java Virtual Machine Stacks)也是線程私有的,它的生命周期與線程相同。

Java虛拟機棧描述的是Java方法(差別于native的本地方法)執行的記憶體模型:每個方法被執行的時候都會同時建立一個棧幀(Stack Frame)用于存儲局部變量表、操作棧、動作連結、方法出口等資訊。每個方法被調用直至執行完成的過程,就對應着一個棧幀在虛拟機棧中從入棧到出棧的過程。

  1. 本地方法棧(Native Method Stacks)

與虛拟機棧所發揮的作用是非常相似的,其差別不過是虛拟機棧為虛拟機執行Java方法(也就是位元組碼)服務,而本地方法棧則為虛拟機所使用到的Native方法服務。

  1. 方法區

有哪些方法可以判斷一個對象已經可以被回收,JVM怎麼判斷一個對象已經消亡可以被回收?

①引用計數算法

給對象中添加一個引用計數器,每當有一個地方引用它時,計數器就加1;當引用失效時,計數器值就減1;任何時刻計數器都為0的對象就是不可能再被使用的。

Java語言沒有選用引用計數法來管理記憶體,因為引用計數法不能很好的解決循環引用的問題。

②根搜尋算法

在主流的商用語言中,都是使用根搜尋算法來判定對象是否存活的。

GC Root Tracing 算法思路就是通過一系列的名為"GC Roots"的對象作為起始點,從這些節點開始向下搜尋,搜尋所走過的路徑稱為引用鍊(Reference Chain),當一個對象到GC Roots沒有任何引用鍊相連,即從GC Roots到這個對象不可達,則證明此對象是不可用的。

哪些對象可以作為GC Roots?

  1. 虛拟機棧(棧幀中的本地變量表)中的引用的對象
  2. 方法區中的類靜态屬性引用的對象
  3. 方法區中的常量引用的對象
  4. 本地方法棧中JNI(Native方法)的引用對象