一、初識JVM(虛擬機)
JVM是Java Virtual Machine(Java虛擬機)的縮寫,JVM是一種用於計算設備的規范,它是一個虛構出來的計算機,是通過在實際的計算機上仿真模擬各種計算機功能來實現的。
引入Java語言虛擬機后,Java語言在不同平台上運行時不需要重新編譯。Java語言使用Java虛擬機屏蔽了與具體平台相關的信息,使得Java語言編譯程序只需生成在Java虛擬機上運行的目標代碼(字節碼),就可以在多種平台上不加修改地運行。
二、Java為什么是“平台無關的編程語言”?
- Java虛擬機是一個可以執行Java字節碼的虛擬機進程。
- Java源文件被編譯成能被Java虛擬機執行的字節碼文件(.class文件)。
- Java被設計成允許應用程序可以運行在任意的平台,而不需要程序員為每一個平台單獨重寫或者是重新編譯。
- Java虛擬機讓這個變為可能,因為它知道底層硬件平台的指令長度和其他特性。
三、Java內存結構
- 線程共享:方法區、堆
- 線程私有:java棧、本地方法棧、程序計數器
Java堆(Heap)
是Java虛擬機所管理的內存中最大的一塊,在虛擬機啟動時創建。線程共享,此內存區域的唯一目的就是存放對象實例。
方法區(Method Area)
線程共享,它用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據。
程序計數器(Program Counter Register)
線程私有,是一塊較小的內存空間,它的作用可以看做是當前線程所執行的字節碼的行號指示器。
JVM棧(JVM Stacks)
線程私有,生命周期與線程相同。
虛擬機棧描述的是Java方法執行的內存模型:每個方法被執行的時候都會同時創建一個棧幀(Stack Frame)用於存儲局部變量表、操作棧、動態鏈接、方法出口等信息。每一個方法被調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中從入棧到出棧的過程。
本地方法棧(Native Method Stacks)
線程私有,與虛擬機棧所發揮的作用是非常相似的,其區別不過是虛擬機棧為虛擬機執行Java方法(也就是字節碼)服務,而本地方法棧則是為虛擬機使用到的Native方法服務。
PS: Native Method就是一個java調用非java代碼的接口
四、JVM的對象分配規則
- 對象優先分配在Eden區【使用空間】,如果Eden區沒有足夠的空間時,虛擬機執行一次Minor GC【垃圾回收】。
- 大對象直接進入老年代(大對象是指需要大量連續內存空間的對象)。這樣做的目的是避免在Eden區和兩個Survivor區之間發生大量的內存拷貝(新生代采用復制算法收集內存)。
- 長期存活的對象進入老年代。虛擬機為每個對象定義了一個年齡計數器,如果對象經過了1次Minor GC(年輕代收集)那么對象會進入Survivor區,之后每經過一次Minor GC那么對象的年齡加1,知道達到閥值對象進入老年區。
- 動態判斷對象的年齡。如果Survivor區中相同年齡的所有對象大小的總和大於Survivor空間的一半,年齡大於或等於該年齡的對象可以直接進入老年代。
- 空間分配擔保。每次進行Minor GC時,JVM會計算Survivor區移至老年區的對象的平均大小,如果這個值大於老年區的剩余值大小則進行一次Full GC,如果小於檢查HandlePromotionFailure設置,如果true則只進行Monitor GC,如果false則進行Full GC。
術語說明
- Young Generation(新生代):分為:Eden區和Survivor區,Survivor區有分為大小相等的From Space和To Space。
- Old Generation(老年代): Tenured區,當 Tenured區空間不夠時, JVM 會在Tenured區進行 major collection。
- Minor GC:新生代GC,指發生在新生代的垃圾收集動作,因為java對象大多都具備朝生夕死的特性,所以Minor GC非常頻繁,一般回收速度也比較快。
- Major GC:發生老年代的GC,對整個堆進行GC。出現Major GC,經常會伴隨至少一次Minor GC(非絕對)。MajorGC的速度一般比minor GC慢10倍以上。
- Full GC:整個虛擬機,包括永久區、新生區和老年區的回收。