GC 和 JVM的一些知識點

閱讀文本大概需要3分鐘。

0x01:五大區域

  • 程序計數器(Program Counter Register):當前線程所執行的字節碼的行號指示器,字節碼解析器的工作是通過改變這個計數器的值,來選取下一條需要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能,都需要依賴這個計數器來完成;(私有)

  • Java 虛擬機棧(棧)(Java Virtual Machine Stacks):用於存儲局部變量表、操作數棧、動態鏈接、方法出口等信息;(私有)

  • 本地方法棧(Native Method Stack):與虛擬機棧的作用是一樣的,只不過虛擬機棧是服務 Java 方法的,而本地方法棧是爲虛擬機調用 Native 方法服務的;(私有)

  • Java堆((堆)Java Heap):Java虛擬機中內存最大的一塊,是被所有線程共享的,幾乎所有的對象實例都在這裏分配內存;(共享)

  • 方法區(Methed Area):用於存儲已被虛擬機加載的類信息、常量、靜態變量】即時編譯後的代碼等數據。(共享)

        JVM的內存結構包括五大區域:程序計數器、虛擬機棧、本地方法棧、堆區、方法區。其中程序計數器、虛擬機棧、本地方法棧3個區域隨線程而生、隨線程而滅,因此這幾個區域的內存分配和回收都具備確定性,就不需要過多考慮回收的問題,因爲方法結束或者線程結束時,內存自然就跟隨着回收了。而Java堆區和方法區則不一樣這部分內存的分配和回收是動態的,正是垃圾收集器所需關注的部分。

        垃圾收集器在對堆區和方法區進行回收前,首先要確定這些區域的對象哪些可以被回收,哪些暫時還不能回收,這就要用到判斷對象是否存活的算法!

判斷對象死沒死,常見的有兩種方法:

  • 引用計數法:爲每個對象創建一個引用計數,有對象引用時計數器 +1,引用被釋放時計數 -1,當計數器爲 0 時就可以被回收。它有一個缺點不能解決循環引用的問題;

  • 可達性計數法:從 GC Roots 開始向下搜索,搜索所走過的路徑稱爲引用鏈。當一個對象到 GC Roots 沒有任何引用鏈相連時,則證明此對象是可以被回收的。

0x02:JVM有哪些垃圾回收算法

  • 標記-清除算法:標記無用對象,然後進行清除回收。

缺點:效率不高,標記和清除循環兩遍,對分配的內存來說,往往是連續的比較好,因爲這樣有利於分配大數據的對象。倘若當前內存中都是小段的內存碎片,會知道需要分配大段內存時,沒有可以放置的位置,而觸發內存回收。也就是空間不足而導致頻繁GC和性能下降。

  • 標記-整理算法:標記無用對象,讓所有存活的對象都向一端移動,然後直接清除掉端邊界以外的內存。

缺點:向一端移動,有太多的小而雜的對象來說,每次移動和計算都是很複雜的過程。因此在使用場景上,就註定限制了標記整理算法的使用不太適合頻繁創建和回收對象的內存中。

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

缺點:內存使用率不高,只有原來的一半。

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

0x03: Minor GC、Minor GC和Full GC觸發條件

Minor GC:從年輕代空間(包括 Eden 和 Survivor 區域)回收內存被稱爲 Minor GC;

Minor GC:對老年代GC稱爲Major GC;

Full GC:而Full GC是對整個堆來說的;

在最近幾個版本的JDK裏默認包括了對永生代即方法區的回收(JDK8中無永生代了),出現Full GC的時候經常伴隨至少一次的Minor GC,但非絕對的。Major GC的速度一般會比Minor GC慢10倍以上。下邊看看有那種情況觸發JVM進行Full GC及應對策略。

  • Minor GC觸發條件:當Eden區滿時,觸發Minor GC。

  • Full GC觸發條件:

(1)System.gc()方法的調用

       此方法的調用是建議JVM進行Full GC,雖然只是建議而非一定,但很多情況下它會觸發 Full GC,從而增加Full GC的頻率,也即增加了間歇性停頓的次數。強烈影響建議能不使用此方法就別使用,讓虛擬機自己去管理它的內存,可通過通過-XX:+ DisableExplicitGC來禁止RMI(Java遠程方法調用)調用System.gc。

(2)老年代空間不足

      舊生代空間只有在新生代對象轉入及創建爲大對象、大數組時纔會出現不足的現象,當執行Full GC後空間仍然不足,則拋出如下錯誤:java.lang.OutOfMemoryError: Java heap space 爲避免以上兩種狀況引起的FullGC,調優時應儘量做到讓對象在Minor GC階段被回收、讓對象在新生代多存活一段時間及不要創建過大的對象及數組。

(3)方法區空間不足

      JVM規範中運行時數據區域中的方法區,在HotSpot虛擬機中又被習慣稱爲永生代或者永生區,Permanet Generation中存放的爲一些class的信息、常量、靜態變量等數據,當系統中要加載的類、反射的類和調用的方法較多時,Permanet Generation可能會被佔滿,在未配置爲採用CMS GC的情況下也會執行Full GC。如果經過Full GC仍然回收不了,那麼JVM會拋出如下錯誤信息:

java.lang.OutOfMemoryError: PermGen space

爲避免Perm Gen佔滿造成Full GC現象,可採用的方法爲增大Perm Gen空間或轉爲使用CMS GC。

(4)通過Minor GC後進入老年代的平均大小大於老年代的可用內存

      如果發現統計數據說之前Minor GC的平均晉升大小比目前old gen剩餘的空間大,則不會觸發Minor GC而是轉爲觸發full GC

(5)由Eden區、From Space區向To Space區複製時,對象大小大於To Space可用內存,則把該對象轉存到老年代,且老年代的可用內存小於該對象大小

參考:https://www.jianshu.com/p/1196cf7cb8b8

https://www.cnblogs.com/lhh666/p/11545502.html

推薦閱讀

Spring Boot 最流行的 16 條實踐

SSM框架的面試常見問題

【分佈式】緩存穿透、緩存雪崩,緩存擊穿解決方案

阿里P7給出的一份超詳細 Spring Boot 知識清單

關注我每天進步一點點

你點的每個在看,我都認真當成了喜歡

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