什麼是JVM?
JVM:Java虛擬機(英語:Java Virtual Machine,縮寫:JVM),一種能夠執行Java字節碼的虛擬機,以堆棧結構機器來實現。最早由Sun微系統所研發並實現第一個實現版本,是Java平臺的一部分,能夠執行以Java語言寫作的軟件程序。
通過維基百科的解釋,可以瞭解到JVM虛擬機,是Java程序運行的基座。Java程序需要在JVM上纔可以運行。可以理解爲Java程序是在JVM上運行,而不去和底層系統進行交互。JVM的作用是將代碼轉化爲機器能理解的語言,再由機器去執行代碼。
JVM的構成有哪些?
JVM主要由運行數據區、執行引擎、本地方法區、本地方法庫、類機載器,這五個部分組成。
執行引擎(execution Engine):將字節碼指令解釋/編譯爲對應平臺上的本地機器指令。
本地方法接口(Java Native Interface):調用其他語言寫的方法。
本地方法庫:字面意思,可以理解爲給本地方法接口提供的操作庫。
類加載器(Class Loader):類加載器內容很多,獨立章節講
運行時內存空間(Runtime Data Area):JVM關鍵內容,獨立章節講
運行時內存空間
什麼是運行時內存空間?
指的是程序運行的時候,JVM的內存組成。不同區域的內存空間負責不同的功能。
運行時內存空間有哪些部分組成?
· 程序計數器(Program Counter Register):
· 線程是沒有記憶的,一旦線程被阻塞後再喚醒就不知道自己要做什麼,程序計數器用於記錄線程執行到哪條指令。
· 保存當前線程所正在執行的字節碼指令的地址
· 爲了在線程切換之後能恢復到正確的執行位置,每個線程都有獨立的程序計數器
· 程序計數器內存區域是虛擬機中唯一沒有規定OOM情況的區域
· 虛擬機棧(VM Stack):
· 是線程私有的內存,生命週期和線程相同,方法在執行的時候,都會在虛擬機棧中創建一個棧幀(Stack Frame),用於存儲局部變量表、操作數棧,動態鏈接、方法出口等信息。
· 表示方法運行時候,在JVM中的內存模型,最小單位是棧幀。存儲存儲局部變量表、操作數棧,動態鏈接、方法出口。
· 局部變量表:存儲臨時的8個基本數據類型、對象引用地址、returnAddress(保存return後要執行的字節碼的指令地址)類型。
· 局部變量表在class文件中已經定義好最大大小
· 局部變量表的容量以變量槽(Slot)爲最小單位,32位的虛擬機中一個Slot可以存放32位以內的數據。
· 對於64位長度的數據類型(long double),虛擬機會以高位對齊的方式爲其分配兩個連續的Slot空間。
· Slot是可以重用的,當Slot中的變量超出了作用域,那麼下一次分配Slot的時候,會覆蓋原來的數據,Slot對對象的引用會影響GC(如果被引用,那麼將不會被回收)
· 系統不會爲局部變量賦予初始值。
· 操作數棧
· 數據操作區域,作爲數據臨時變更的空間。比如代碼有i=66+1,66+1這個操作在操作數棧中計算,然後存入局部變量表中。
· 在編譯時期已經確定最大大小
· 動態鏈接
· 存儲調用別的方法的地址信息。因爲在class文件中,所有的變量和方法引用都是作爲符號引用,保存在class文件的常量池中,所以動態鏈接的作用是將這些符號引用轉化爲直接引用。比如方法A中要調用方法B,class文件中,寫的是B方法名稱,在動態鏈接中存儲方法B的名稱和地址對應關係。
· 方法返回地址
· 字面意思,有兩種返回,正常返回和異常拋出。
· 本地方法棧(Nactive Method Stack):
· 和虛擬機棧的方法類似,只不過服務於Navite方法。
· Java堆(heap):
Java虛擬機中內存最大的一塊,是被所有線程共享的,幾乎所有的對象實例都在這裏分配內存。
· 堆的特點:
· 先進先出
· 是JVM中佔用空間最大的內存,並且運行時動態分配內存大小
· 所有線程共享的內存
· GC的主要場所
· JVM啓動的時候創建堆
· 邏輯上連續的,物理上非連續(內存地址不連續)
· 堆的構成
· PermGen Space:永久代。永久保存的區域,用於存放Class和Meta信息,Class在被Load的時候放入該區域,GC不會對PermGen Space進行清理,所以如果有很多的Class被load,那麼會跑出OOM異常。JDK1.8之後不存在永久代,改爲元空間,也不需要進行內存分配,元數據直接使用系統內存,而不是JVM內存。
· Young Space:新生代對象,保存剛實例化的對象。當該區被填滿時,GC會將對象移到Old Space中。
· 當中又被分爲Eden區、From Survivor區、To Survivor區,存在兩個Survivor區域是因爲GC要進行復制算法,所以需要兩塊區域。由於有Survivor區的存在,Eden區不會直接向老年代直接傳送對象,減少Full GC的發生,
· Eden區、From Survivor區、To Survivor區的默認內存比例爲8:1:1。
· Old Space:老年代的對象,在多次Minor GC之後,依舊存在對象會被轉移到年老代,老年代的內存空間應該要比年輕代大。與Young Space的內存空間比爲1:2。
· 堆內存分配
· 最開的內存大小由Xms指定,默認是物理內存的1/64
· 最大的內存由Xmx指定,默認是物理內存的1/4
· 堆內存空間小於40%的時候,JVM會增加堆內存大小
· 堆內存空間大於70%的時候,JVM會減少堆內存的大小
· 一般將Xms和Xmx設置爲同一個值,禁止JVM劃分堆內存,優化性能
· 非堆內存分配(永久代內存分配)
· 使用-XX:PermSize設置非堆內存的初始值,默認是物理內存的1/64
· 使用-XX:MaxPermSize設置非堆內存的最大值,默認是物理內存的1/4
· 垃圾回收機制
· MinorGC:清理年輕代的內存空間,垃圾回收過程是(複製->清空->互換),採用的算法是複製算法。
· 過程:當Eden區滿的時候,釋放在Eden中所有不活躍的對象,活躍的對象放入Survivor區域,並且對象的年齡+1,大對象會直接進入老年區(-XX:PretenureSizeThreshold參數可以設置多大的對象可以直接進入老年區)。如果Survivor區域已經滿了,那麼會對Survivor進行MinorGC,將年齡達到設置值(默認15)的對象放入老年區。
· MajorGC:老年代內存不足時,觸發老年代GC。採用標記清除法或者標記整理算法的混合實現,該GC不會有MinorGC那麼頻繁,並且一次MajorGC要比MinorGC時間更長。
· FullGC:清理整個堆空間
· 方法區(Method Area):
· 所有線程共享的,用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯後的代碼等數據。
· 直接內存
· 在JDK1.4中引入NIO之後,爲了視線一種通過native函數直接分配對外內存的,這一切是通過兩個概念實現的:channel和buffer。會出現OOM的情況,是受物理機器的內存限制的。
· 直接內存並不受JVM內存回收管理
PS
Q:Java程序是不是隻能運行在JVM上?
A:!!!!!---!!!!!從狹義上講,JVM主要的任務是將class文件翻譯爲機器碼。只要能翻譯class文件變爲機器碼,那就不需要JVM來運行class文件。從廣義上講,能翻譯class文件爲機器碼的東西,可以稱之爲JVM。
Q:JDK、JRE和JVM的區別?
A:JDK是 Java 的開發工具包,提供了 Java 應用程序開發所需的工具和庫。JDK 包括 Java 編譯器(javac)、Java 虛擬機(JVM)和 Java 庫等組件。JDK 可以用於開發 Java 應用程序、Java Servlet 和 Java Server Pages(JSP)等服務器端應用程序,以及 Java 應用程序的桌面版本等。
JRE是 Java 的運行環境,是 Java 應用程序運行的基本環境。JRE 包括 Java 虛擬機(JVM)、Java 標準庫和其他組件。JRE 只能用於運行 Java 應用程序,不能用於開發 Java 應用程序。
JVM是 Java 虛擬機,是 Java 應用程序的運行時環境,可以在不同的操作系統上運行 Java 應用程序。JVM 實現了 Java 字節碼的解釋和執行,並提供了內存管理、垃圾回收等機制。JVM 是跨平臺的,可以在不同的硬件平臺和操作系統上運行。