一.虛擬機的構成
虛擬結主要由運行時數據區、執行引擎、類加載器三者構成:
而我們所說的JVM內存模型指的就是運行時數據區,下面具體分析一下運行時數據區:
二.運行時數據區組成和各個區域的作用
我們看到運行時數據區可以分為線程共享和線程不共享兩部分,其中堆內存和方法區線程共享,本地方法棧、虛擬機棧、程序計數器線程不共享。
接下來我們介紹每一個區域的作用:
2.1.程序計數器
程序計數器(Program Counter Register),也有稱作為PC寄存器。想必學過匯編語言的朋友對程序計數器這個概念並不陌生,在匯編語言中,程序計數器是指CPU中的寄存器,它保存的是程序當前執行的指令的地址(也可以說保存下一條指令的所在存儲單元的地址),當CPU需要執行指令時,需要從程序計數器中得到當前需要執行的指令所在存儲單元的地址,然后根據得到的地址獲取到指令,在得到指令之后,程序計數器便自動加1或者根據轉移指針得到下一條指令的地址,如此循環,直至執行完所有的指令。
2.2虛擬機棧
虛擬機棧也叫java棧,棧中存儲的是幀棧,每一個方法對應一個幀棧,方法執行完畢后進行彈棧,讓出棧內存,幀棧中存儲着方法中定義的變量,如果是基本數據類型,就在棧中進行值的存儲,如果是引用數據類型,存儲的是引用指向對象的地址。
虛擬機棧也叫棧內存,是在線程創建時創建,它的生命期是跟隨線程的生命期,線程結束棧內存也就釋放,對於棧來說不存在垃圾回收問題,只要線程一結束,該棧就 Over,所以不存在垃圾回收。也有一些資料翻譯成JAVA方法棧,大概是因為它所描述的是java方法執行的內存模型,每個方法執行的同時創建幀棧(Strack Frame)用於存儲局部變量表(包含了對應的方法參數和局部變量),操作棧(Operand Stack,記錄出棧、入棧的操作),動態鏈接、方法出口等信息,每個方法被調用直到執行完畢的過程,對應這幀棧在虛擬機棧的入棧和出棧的過程。
局部變量表存放了編譯期可知的各種基本數據類型(boolean、byte、char、short、int、float、long、double)、對象的引用(reference類型,不等同於對象本身,根據不同的虛擬機實現,可能是一個指向對象起始地址的引用指針,也可能是一個代表對象的句柄或者其他與對象相關的位置)和 returnAdress類型(指向下一條字節碼指令的地址)。局部變量表所需的內存空間在編譯期間完成分配,在方法在運行之前,該局部變量表所需要的內存空間是固定的,運行期間也不會改變。
2.3本地方法棧
和虛擬機棧功能相似,不過本地方法棧存儲針對本地方法。
2.4堆內存
堆內存主要用來存儲被創建的對象,一個類new出一個對象,會在堆中開辟內存空間,並在棧中存儲一個引用,存儲着對象在堆中的地址。堆內存中的對象存儲着自己的成員變量,並不保存對象的方法,方法被保存在幀棧中,堆內存也稱為gc堆,是主要用來進行垃圾回收的內存。
2.5方法區
方法區是一個非常重要的區域,也是被線程共享的區域,方法區存儲了每個類的信息(類的名稱、方法信息、字段信息),靜態變量、常量以及編譯后的代碼等。
方法區還包括一個常量池,用來存儲編譯期間生成的字面量和符號引用。這部分內容在類被加載后,都會存儲到方法區中的RCP。值得注意的是,運行時產生的新常量也可以被放入常量池中,比如 String 類中的 intern() 方法產生的常量。
常量池就是這個類型用到的常量的一個有序集合。包括直接常量(基本類型,String)和對其他類型、方法、字段的符號引用.
三.常量池的使用
3.1什么是常量?
常量是指被final修飾的變量,值一旦確定就無法改變。
final可以修飾靜態變量、實例變量和局部變量。
3.2Clss文件中的常量池
我們知道方法區中存放着class文件的信息,還包括用來存儲class常量的常量池,方法區中還存在運行時常量池兩者什么關系?
常量池主要用來存放兩大類常量:字面量和符號引用量,字面量相當於Java語言的常量,如文本字符串,聲明為final的常量等,符號引用包括以下三種
類和接口的全限定名
字段名稱和描述符
方法名稱和描述符
3.3方法區中的運行常量池
class文件中的常量池中的內容會在類加載后進入方法區的運行時常量池。相對於常量池,運行時常量池的重要特征是具有動態性,java並不要求常量只有在編譯器才會產生,運行期間也可以將新的常量存放入池中,這種特性用的最多的String類中的intern()方法。
3.4常量池的作用和==號的意義
常量池是為了避免頻繁的創建和銷毀對象造成系統性能的浪費,實現了對象的共享。
==號比較基本數據類型,就是比值,比較引用數據類型比較的是內存中存放的地址。
3.2常量池的應用
對於byte、short、long、char、boolean對應的包裝器類都有對應的常量池,這五種包裝器類默認創建在-128到127的對象會存放在在緩存中。
對於兩種浮點數沒有實現常量池技術。
3.4String類和常量池
String str1="abc"; String str2=new String("abc"); System.out.println(str1==str2);
結果為false;