JVM解析(一) JVM 運行時內存空間

什麼是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 是跨平臺的,可以在不同的硬件平臺和操作系統上運行。

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