jvm基礎必備

目錄

前言

硬件(多cpu)的效率與一致性

jvm內存模型

一、jvm結構

1.1 整體結構

1.2 內存區

1 堆

2 非堆

二、垃圾回收

2.1 如何檢測

2.2 如何回收

2.3 垃圾回收分類

三、jvm工具


前言

硬件(多cpu)的效率與一致性

如上圖所示,基於高速緩存的存儲交互很好的解決了處理器與內存之間的矛盾,也引入了新的問題:緩存一致性問題。在多處理器系統中,每個處理器有自己的高速緩存,而他們又共享同一塊內存(下文成主存,main memory 主要內存),當多個處理器運算都涉及到同一塊內存區域的時候,就有可能發生緩存不一致的現象。爲了解決這一問題,需要各個處理器運行時都遵循一些協議,在運行時需要將這些協議保證數據的一致性。這類協議包括MSI、MESI、MOSI、Synapse、Firely、DragonProtocol等。

 

jvm內存模型

虛擬機內存模型中定義的訪問操作與物理計算機處理的基本一致!

如上圖所示,Java中通過多線程機制使得多個任務同時執行處理,所有的線程共享JVM內存區域main memory,而每個線程又單獨的有自己的工作內存,當線程與內存區域進行交互時,數據從主存拷貝到工作內存,進而交由線程處理(操作碼+操作數)。

 

一、jvm結構

1.1 整體結構

整體如下圖所示:

 

如圖所示,JVM主要包括四個部分:

1.類加載器(ClassLoader):在JVM啓動時或者在類運行時將需要的class加載到JVM中。(右圖表示了從java源文件到JVM的整個過程,可配合理解。 關於類的加載機制,可以參考http://blog.csdn.net/tonytfjing/article/details/47212291

2.執行引擎:負責執行class文件中包含的字節碼指令(執行引擎的工作機制,這裏也不細說了,這裏主要介紹JVM結構);

3.內存區(運行時數據區):是在JVM運行的時候操作所分配的內存區。

4.本地方法接口:主要是調用C或C++實現的本地方法及返回結果。

 

1.2 內存區

如圖所示,內存區包括以下幾個部分:

  • 方法區(Method Area):用於存儲類結構信息的地方,包括常量池、靜態變量、構造函數等。雖然JVM規範把方法區描述爲堆的一個邏輯部分, 但它卻有個別名non-heap(非堆),所以大家不要搞混淆了。方法區還包含一個運行時常量池。jdk1.8以前使用永久帶來實現,jdk1.8開始使用元數據區(meta space)來實現。

  • 堆(Heap):存儲java實例或者對象的地方,這塊是GC的主要區域。從存儲的內容我們可以很容易知道,方法區和堆是被所有java線程共享的。
  • 棧(Stack):java棧總是和線程關聯在一起,每當創建一個線程時,JVM就會爲這個線程創建一個對應的java棧。在這個java棧中又會包含多個棧幀,每運行一個方法就創建一個棧幀,用於存儲局部變量表、操作棧、方法返回值等。每一個方法從調用直至執行完成的過程,就對應一個棧幀在java棧中入棧到出棧的過程。所以java棧是現成私有的。
  • 本地方法棧(Native Method Stack):和java棧的作用差不多,只不過是爲JVM使用到的native方法服務的。
     
  • 程序計數器(PC Register):用於保存當前線程執行的內存地址。由於JVM程序是多線程執行的(線程輪流切換),所以爲了保證線程切換回來後,還能恢復到原先狀態,就需要一個獨立的計數器,記錄之前中斷的地方,可見程序計數器也是線程私有的。

1 堆

年輕代:是所有新對象產生的地方。年輕代被分爲3個部分——Eden區和兩個Survivor區(From和to)。當Eden區被對象填滿時,就會執行Minor GC。並把所有存活下來的對象轉移到其中一個survivor區(假設爲from區)。Minor GC同樣會檢查存活下來的對象,並把它們轉移到另一個survivor區(假設爲to區)。這樣在一段時間內,總會有一個空的survivor區。經過多次GC週期後,仍然存活下來的對象會被轉移到年老代內存空間。通常這是在年輕代有資格提升到年老代前通過設定年齡閾值來完成的。需要注意,Survivor的兩個區是對稱的,沒先後關係,from和to是相對的。使用copy算法進行內容回收。

年老代:在年輕代中經歷了N次回收後仍然沒有被清除的對象,就會被放到年老代中,可以說他們都是久經沙場而不亡的一代,都是生命週期較長的對象。通常會在老年代內存被佔滿時將會觸發Full GC,回收整個堆內存。回收算法基本是標記-清除(mark-sweep)或者標記-壓縮(mark-compact)。

 

2 非堆

永久代:永久帶又叫Perm區,只存在於hotspot jvm中,並且只存在於jdk7和之前的版本中;jdk8中已經徹底移除了永久帶,jdk8中引入了一個新的內存區域叫metaspace。

(1)並不是所有的jvm中都有永久帶,ibm的j9,oracle的JRocket都沒有永久帶。

(2)永久帶是實現層面的東西。

(3)永久帶裏面存的東西基本上就是方法區規定的那些東西。

因此,我們可以說,永久帶是方法區的一種實現,當然,在hotspot jdk8中metaspace可以看成是方法區的一種實現。

hotspot jdk8中移除了永久帶以後的內存結構:

 

 

二、垃圾回收

垃圾收集器一般必須完成兩件事:檢測出垃圾;回收垃圾。

2.1 如何檢測

引用計數法:給一個對象添加引用計數器,每當有個地方引用它,計數器就加1;引用失效就減1。

可達性分析算法:以根集對象爲起始點進行搜索,如果有對象不可達的話,即是垃圾對象。這裏的根集一般包括java棧中引用的對象、方法區常量池中引用的對象、本地方法中引用的對象等。

2.2 如何回收

1.標記-清除(Mark-sweep)
最基礎的垃圾收集算法,缺點是效率不高,造成內存碎片

2.複製(Copying)
算法簡單,缺點是內存縮小一半

3.標記-整理(Mark-Compact)
適合老年代

4.分代收集算法

這是當前商業虛擬機常用的垃圾收集算法。分代的垃圾回收策略,是基於這樣一個事實:不同的對象的生命週期是不一樣的。因此,不同生命週期的對象可以採取不同的收集方式,以便提高回收效率。
新生代:copy算法
老年代:標記清除或者標記-整理

 

2.3 垃圾回收分類

       1、大多數情況下,對象在新生代Eden區分配。當Eden區沒有足夠空間進行分配時,虛擬機將發起一次MinorGC
  2、大對象直接進入老年代,所謂大對象是指,需要大量連續內存空間的java對象,虛擬機提供了一個-XX:PretenureSizeThreshold參數,令大於這個設置值的對象直接在Old老年代分配。這樣做的目的是避免在Eden區及兩個Survivor區之間發生大量的內存複製
  3、長期存活的對象將進入老年代,虛擬機給每個對象定義了一個對象年齡計數器,如果對象在Eden出生並經過第一次Minor GC後仍然存活,並且能被Survivor容納的話,將被移動到Survivor空間中,並且對象年齡設爲1,對象在Survivor區中每熬過一次MinorGC,年齡就增加1歲,默認增加到15歲時改對象就會晉升到老年代,晉升到老年代的年齡閾值,可以通過-XX:MaxTenuringThreshold設置。虛擬機並不是永遠要求對象年齡必須達到設置的值才能晉升到老年代,如果在Survivor空間中相同年齡所有對象大小的總和大於Survivor空間的一半,年齡大於或等於該年齡的對象就可以直接進入老年代。

 

三、jvm工具


四、參考文章
JVM內存結構,爲什麼需要GC?
深入理解JVM—JVM內存模型
JVM的方法區和永久代的關係
BATJ面試必會|Jvm 虛擬機篇

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