一 、前言
JVM是什么,我想諸位肯定都清楚。
好吧,我還是簡答說一下JVM即Java虛擬機(夠簡單吧 233333)。
雖然說,所有拋開操作系統,講虛擬機的內容,都是耍流氓。但是,貧僧不修善果,就愛殺人放火,就愛耍流氓。好吧,扯遠了。
言歸正傳,JVM這是第三遍重溫了。第一遍讀時,還是在飛機上讀的,就記得飛機上的陽光很刺眼,肚子很難受,從書中汲取的知識很少。第二遍讀時,是在做地鐵時看完的。地鐵很擠,書很好看。如今,距離上次讀完,已有一載有余,一年發生了很多事,朋友離開,公司散伙,親人重病。期間明白了很多道理。一個是,一定要好好的關愛你的親人。一個是,對於人重要的東西只有兩樣,健康的身體,以及獨立的靈魂。最近讀完了史鐵生的《我與地壇》對這兩點也是感觸頗多。
又扯遠了。下面進入正題。
二、 內存划分
總體划分如下:
三、運行時數據區域
運行時數據區域,我們可以分為線程私有的數據區域,與線程共享的數據區域。線程私有,也就是線程內的數據,是能且僅能讓創建它的線程訪問。線程共享,是任何線程都可以訪問共享的此數據。
1、線程私有
(1)程序計數器
- 程序計數器可以視為當前線程執行的字節碼行數指示器。(程序計數器是什么)
- 多線程運行時,本質上,是線程的輪流切換。這一點,如果對操作系統還有記憶的同學,可能感覺如此之熟悉,是的單核的操作系統中,CPU在執行多任務時,就是將每個任務都執行一點,宏觀意義上來講,就達到了多任務同時進行的感覺。而當虛擬機中多線程執行時,線程執行了一半,就執行其他線程了,又一次回到此線程時,如何確保可以繼續執行線程,這里,就是程序計數器的意義所在了。(為什么要有程序計數器)
- 一個線程有且僅有一個程序計數器。(有第一點和第二點而得出的結論)
(2)java虛擬機棧
[1]棧幀
在每個方法被創建時,同時也會創建一個棧幀。
一個方法被調用到被執行完畢的過程,就是一個棧幀,在虛擬機棧中,從入棧到出棧的過程。
[2]棧幀的數據結構
一個棧幀中包括了局部變量表、操作數棧、動態鏈接、以及方法出口
這里我們詳細的來說一下他的局部變量表
1)存放了基礎數據類型。
2)存放了對象的引用
3)存放了returnAddress:指向一條直字節碼令的地址
[3]基礎數據類型擴展
重溫此結的時候,突然想到了基礎數據的一個共同點。
他們都可以被轉為為int
public static void main(String[] args) {
int i = 1;
short s = 1;
float f = 1f;
double d = 1;
long l = 1L;
char c = 63;
byte b2 = 1;
boolean b = 1;
System.out.println("輸出char>>"+c);
}
以上代碼在編譯期間,最后一行,也就是boolean會報錯,但是學過c或c++的都知道,bool類型,本質上,true為1,false為0。
而其他的都是可以正常賦值的。
char的賦值,大家可以猜猜,輸出的是多少。是63的ASCII值 "?"
輸出char>>?
(3)本地方法棧
本地方法棧,他與虛擬機棧類似(數據結構以及功能等方面)
不同的是,虛擬機棧執行的是java方法(編譯出的字節碼)。而本地方法棧執行的是Native方法。比如:
Thread類中的
private native void start0();
//調用dll或其他文件內方法
public native static void Hello();
有些虛擬機,他的本地方法棧與虛擬機棧會合並。
2、線程共享
(1)java堆
- 堆內的數據,是所有線程共享的。
- 幾乎所有的對象實例都在此存儲,因此,java堆又被稱為GC堆
(2)方法區
[1]方法區的數據結構
類信息:包括了類的版本、類中的字段、方法、接口以及常量池。常量池在編譯期就會確認並生成。
常量。
靜態常量。
編譯后的代碼。
[2] 邏輯上是堆的一部分,但他的別名是非堆。
2、非運行時數據區域
(1)直接內存
NIO使用此塊內存,以提高讀寫性能
四、參考
《深入理解java虛擬機》