JVM結構及堆的划分


一、JVM結構

1、類加載子系統與方法區

  類加載子系統負責從文件系統或者網絡中加載Class信息,加載的類信息存放於一塊稱為方法區的內存空間。除了類的信息外,方法區中可能還會存放運行時常量池信息,包括字符串字面量和數字常量(這部分常量信息是Class文件中常量池部分的內存映射)。

2、Java堆

  java堆在虛擬機啟動的時候建立,它是java程序最主要的內存工作區域。幾乎所有的java對象實例都存放在java堆中。堆空間是所有線程共享的,這是一塊與java應用密切相關的內存空間。

3、直接內存

  java的NIO庫允許java程序使用直接內存。直接內存是在java堆外的、直接向系統申請的內存空間。通常訪問直接內存的速度會優於java堆。因此出於性能的考慮,讀寫頻繁的場合可能會考慮使用直接內存。由於直接內存在java堆外,因此它的大小不會直接受限於Xmx指定的最大堆大小,但是系統內存是有限的,java堆和直接內存的總和依然受限於操作系統能給出的最大內存。

4、垃圾回收系統

  垃圾回收系統是java虛擬機的重要組成部分,垃圾回收器可以對方法區、java堆和直接內存進行回收。其中,java堆是垃圾收集器的工作重點。和C/C++不同,java中所有的對象空間釋放都是隱式的,也就是說,java中沒有類似free()或者delete()這樣的函數釋放指定的內存區域。對於不再使用的垃圾對象,垃圾回收系統會在后台默默工作,默默查找、標識並釋放垃圾對象,完成包括java堆、方法區和直接內存中的全自動化管理。

5、java棧

  每一個java虛擬機線程都有一個私有的java棧,一個線程的java棧在線程創建的時候被創建,java棧中保存着幀信息,java棧中保存着局部變量、方法參數,同時和java方法的調用、返回密切相關。

6、本地方法棧

  本地方法棧和java棧非常類似,最大的不同在於java棧用於方法的調用,而本地方法棧則用於本地方法的調用,作為對java虛擬機的重要擴展,java虛擬機允許java直接調用本地方法(通常使用C編寫)。

7、PC寄存器

  PC(Program Counter)寄存器也是每一個線程私有的空間,java虛擬機會為每一個java線程創建PC寄存器。在任意時刻,一個java線程總是在執行一個方法,這個正在被執行的方法稱為當前方法。如果當前方法不是本地方法,PC寄存器就會指向當前正在被執行的指令。如果當前方法是本地方法,那么PC寄存器的值就是undefined。

8、執行引擎

  執行引擎是java虛擬機的最核心組件之一,它負責執行虛擬機的字節碼,現代虛擬機為了提高執行效率,會使用即時編譯(just in time)技術將方法編譯成機器碼后再執行。
  Java HotSpot Client VM(-client),為在客戶端環境中減少啟動時間而優化的執行引擎;本地應用開發使用。(如:eclipse)
  Java HotSpot Server VM(-server),為在服務器環境中最大化程序執行速度而設計的執行引擎。應用在服務端程序。(如:tomcat)

Java HotSpot Client模式和Server模式的區別  

當虛擬機運行在-client模式的時候,使用的是一個代號為C1的輕量級編譯器, 而-server模式啟動的虛擬機采用相對重量級,代號為C2的編譯器. C2比C1編譯器編譯的相對徹底,服務起來之后,性能更高。JDK安裝目錄/jre/lib/(x86、i386、amd32、amd64)/jvm.cfg文件中的內容,-server和-client哪一個配置在上,執行引擎就是哪一個。如果是JDK1.5版本且是64位系統應用時,-client無效。在部分JDK1.6版本和后續的JDK版本(64位系統)中,-client參數已經不起作用了,Server模式成為唯一。

二、堆的划分

1、堆結構分代的意義

  Java虛擬機根據對象存活的周期不同,把堆內存划分為幾塊,一般分為新生代、老年代和永久代(對HotSpot虛擬機而言),這就是JVM的內存分代策略。
  堆內存是虛擬機管理的內存中最大的一塊,也是垃圾回收最頻繁的一塊區域,我們程序所有的對象實例都存放在堆內存中。給堆內存分代是為了提高對象內存分配和垃圾回收的效率。試想一下,如果堆內存沒有區域划分,所有的新創建的對象和生命周期很長的對象放在一起,隨着程序的執行,堆內存需要頻繁進行垃圾收集,而每次回收都要遍歷所有的對象,遍歷這些對象所花費的時間代價是巨大的,會嚴重影響我們的GC效率。
  有了內存分代,情況就不同了,新創建的對象會在新生代中分配內存,經過多次回收仍然存活下來的對象存放在老年代中,靜態屬性、類信息等存放在永久代中,新生代中的對象存活時間短,只需要在新生代區域中頻繁進行GC,老年代中對象生命周期長,內存回收的頻率相對較低,不需要頻繁進行回收,永久代中回收效果太差,一般不進行垃圾回收,還可以根據不同年代的特點采用合適的垃圾收集算法。分代收集大大提升了收集效率,這些都是內存分代帶來的好處。

2、堆結構分代

  Java虛擬機將堆內存划分為新生代、老年代和永久代,永久代是HotSpot虛擬機特有的概念(JDK1.8之后為metaspace替代永久代),它采用永久代的方式來實現方法區,其他的虛擬機實現沒有這一概念,而且HotSpot也有取消永久代的趨勢,在JDK 1.7中HotSpot已經開始了“去永久化”,把原本放在永久代的字符串常量池移出。永久代主要存放常量、類信息、靜態變量等數據,與垃圾回收關系不大,新生代和老年代是垃圾回收的主要區域。

3、新生代(Young Generation)

  新生成的對象優先存放在新生代中,新生代對象朝生夕死,存活率很低,在新生代中,常規應用進行一次垃圾收集一般可以回收70% ~ 95% 的空間,回收效率很高。
  HotSpot將新生代划分為三塊,一塊較大的Eden(伊甸)空間和兩塊較小的Survivor(幸存者)空間,默認比例為8:1:1。划分的目的是因為HotSpot采用復制算法來回收新生代,設置這個比例是為了充分利用內存空間,減少浪費。新生成的對象在Eden區分配(大對象除外,大對象直接進入老年代),當Eden區沒有足夠的空間進行分配時,虛擬機將發起一次Minor GC。
  GC開始時,對象只會存在於Eden區和From Survivor區,To Survivor區是空的(作為保留區域)。GC進行時,Eden區中所有存活的對象都會被復制到To Survivor區,而在From Survivor區中,仍存活的對象會根據它們的年齡值決定去向,年齡值達到年齡閥值(默認為15,新生代中的對象每熬過一輪垃圾回收,年齡值就加1,GC分代年齡存儲在對象的header中)的對象會被移到老年代中,沒有達到閥值的對象會被復制到To Survivor區。接着清空Eden區和From Survivor區,新生代中存活的對象都在To Survivor區。接着, From Survivor區和To Survivor區會交換它們的角色,也就是新的To Survivor區就是上次GC清空的From Survivor區,新的From Survivor區就是上次GC的To Survivor區,總之,不管怎樣都會保證To Survivor區在一輪GC后是空的。GC時當To Survivor區沒有足夠的空間存放上一次新生代收集下來的存活對象時,需要依賴老年代進行分配擔保,將這些對象存放在老年代中。

4、老年代(Old Generationn)

  在新生代中經歷了多次(具體看虛擬機配置的閥值)GC后仍然存活下來的對象會進入老年代中。老年代中的對象生命周期較長,存活率比較高,在老年代中進行GC的頻率相對而言較低,而且回收的速度也比較慢。

5、永久代(Permanent Generationn)

  永久代存儲類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據,對這一區域而言,Java虛擬機規范指出可以不進行垃圾收集,一般而言不會進行垃圾回收。

三、永久代和方法區

1、方法區

  方法區(Method Area)是jvm規范里面的運行時數據區的一個組成部分,jvm規范中的運行時數據區還包含了:pc寄存器、虛擬機棧、堆、方法區、運行時常量池、本地方法棧。主要用來存儲class、運行時常量池、字段、方法、代碼、JIT代碼等。運行時數據區跟內存不是一個概念,方法區是運行時數據區的一部分。方法區是jvm規范中的一部分,並不是實際的實現,切忌將規范跟實現混為一談。

2、永久代

  永久帶又叫Perm區,只存在於hotspot jvm中,並且只存在於jdk7和之前的版本中,jdk8中已經徹底移除了永久帶,jdk8中引入了一個新的內存區域叫metaspace。並不是所有的jvm中都有永久帶,ibm的j9,oracle的JRocket都沒有永久帶,永久帶是實現層面的東西,永久帶里面存的東西基本上就是方法區規定的那些東西。

3、區別

  方法區是規范層面的東西,規定了這一個區域要存放哪些東西,永久帶或者是metaspace是對方法區的不同實現,是實現層面的東西。

4、hotspot jdk8中移除了永久帶以后的內存結構


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM