2.3 運行時資料區(Run-Time Data Areas)
在裝載階段的第(2),(3)步可以發現有運行時資料,堆,方法區等名詞
(2)將這個位元組流所代表的靜態存盤結構轉化為方法區的運行時資料結構
(3)在Java堆中生成一個代表這個類的java.lang.Class物件,作為對方法區中這些資料的訪問入口
說白了就是類檔案被類裝載器裝載進來之后,類中的內容(比如變數,常量,方法,物件等這些資料得要有個去處,也就是要存盤起來,存盤的位置肯定是在JVM中有對應的空間)
2.3.1 官網概括
官網:https://docs.oracle.com/javase/specs/jvms/se8/html/index.html
The Java Virtual Machine defines various run-time data a thread is created and destroyed when the thread exits.
2.3.2 圖解
Each run-time constant pool is allocated from the Java Virtual Machine's method area (§2.5.4).s

2.3.3 初步認識
2.3.3.1 Method Area(方法區)
(1)方法區是各個執行緒共享的記憶體區域,在虛擬機啟動時創建
The Java Virtual Machine has a method area that is shared among all Java Virtual Machine threads.
The method area is created on virtual machine start-up.
(2)雖然Java虛擬機規范把方法區描述為堆的一個邏輯部分,但是它卻又一個別名叫做Non-Heap(非堆),目的是與Java堆區分開來
Although the method area is logically part of the heap,......
(3)用于存盤已被虛擬機加載的類資訊、常量、靜態變數、即時編譯器編譯后的代碼等資料
It stores per-class structures such as the run-time constant pool, field and method data, and the code for methods and constructors, including the special methods (§2.9) used in class and instance initialization and interface initialization.
(4)當方法區無法滿足記憶體分配需求時,將拋出OutOfMemoryError例外
If memory in the method area cannot be made available to satisfy an allocation request, the Java Virtual Machine throws an OutOfMemoryError.
此時回看裝載階段的第2步,將這個位元組流所代表的靜態存盤結構轉化為方法區的運行時資料結構
如果這時候把從Class檔案到裝載的第(1)和(2)步合并起來理解的話,可以畫個圖

值得說明的
JVM運行時資料區是一種規范,真正的實作 在JDK 8中就是Metaspace,在JDK6或7中就是Perm Space
2.3.3.2 Heap(堆)
(1)Java堆是Java虛擬機所管理記憶體中最大的一塊,在虛擬機啟動時創建,被所有執行緒共享,
(2)Java物件實體以及陣列都在堆上分配,
The Java Virtual Machine has a heap that is shared among all Java Virtual Machine threads. The heap is the run-time data area from which memory for all class instances and arrays is allocated.
The heap is created on virtual machine start-up.
此時回看裝載階段的第3步,在Java堆中生成一個代表這個類的java.lang.Class物件,作為對方法區中這些資料的訪問入口
此時裝載(1)(2)(3)的圖可以改動一下

2.3.3.3 Java Virtual Machine Stacks(虛擬機堆疊)
經過上面的分析,類加載機制的裝載程序已經完成,后續的鏈接,初始化也會相應的生效,
假如目前的階段是初始化完成了,后續做啥呢?肯定是Use使用咯,不用的話這樣折騰來折騰去有什么意義?那怎樣才能被使用到?換句話說里面內容怎樣才能被執行?比如通過主函式main呼叫其他方法,這種方式實際上是main執行緒執行之后呼叫的方法,即要想使用里面的各種內容,得要以執行緒為單位,執行相應的方法才行,那一個執行緒執行的狀態如何維護?一個執行緒可以執行多少個方法?這樣的關系怎么維護呢?
(1)虛擬機堆疊是一個執行緒執行的區域,保存著一個執行緒中方法的呼叫狀態,換句話說,一個Java執行緒的運行狀態,由一個虛擬機堆疊來保存,所以虛擬機堆疊肯定是執行緒私有的,獨有的,隨著執行緒的創建而創建,
Each Java Virtual Machine thread has a private Java Virtual Machine stack, created at the same time as the thread.
(2)每一個被執行緒執行的方法,為該堆疊中的堆疊幀,即每個方法對應一個堆疊幀,
呼叫一個方法,就會向堆疊中壓入一個堆疊幀;一個方法呼叫完成,就會把該堆疊幀從堆疊中彈出,
A Java Virtual Machine stack stores frames (§2.6).
A new frame is created each time a method is invoked. A frame is destroyed when its method invocation completes.
- 圖解堆疊和堆疊幀
void a(){
b();
}
void b(){
c();
}
void c(){
}

- 堆疊幀
官網:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.6
堆疊幀:每個堆疊幀對應一個被呼叫的方法,可以理解為一個方法的運行空間,
每個堆疊幀中包括區域變數表(Local Variables)、運算元堆疊(Operand Stack)、指向運行時常量池的參考(A reference to the run-time constant pool)、方法回傳地址(Return Address)和附加資訊,
區域變數表:方法中定義的區域變數以及方法的引數存放在這張表中
區域變數表中的變數不可直接使用,如需要使用的話,必須通過相關指令將其加載至運算元堆疊中作為運算元使用,
運算元堆疊:以壓堆疊和出堆疊的方式存盤運算元的
動態鏈接:每個堆疊幀都包含一個指向運行時常量池中該堆疊幀所屬方法的參考,持有這個參考是為了支持方法呼叫程序中的動態連接(Dynamic Linking),
方法回傳地址:當一個方法開始執行后,只有兩種方式可以退出,一種是遇到方法回傳的位元組碼指令;一種是遇見例外,并且這個例外沒有在方法體內得到處理,

- 結合位元組碼指令理解堆疊幀
javap -c Person.class > Person.txt
Compiled from "Person.java"
class Person {
...
public static int calc(int, int);
Code:
0: iconst_3 //將int型別常量3壓入[運算元堆疊]
1: istore_0 //將int型別值存入[區域變數0]
2: iload_0 //從[區域變數0]中裝載int型別值入堆疊
3: iload_1 //從[區域變數1]中裝載int型別值入堆疊
4: iadd //將堆疊頂元素彈出堆疊,執行int型別的加法,結果入堆疊
5: istore_2 //將堆疊頂int型別值保存到[區域變數2]中
6: iload_2 //從[區域變數2]中裝載int型別值入堆疊
7: ireturn //從方法中回傳int型別的資料
...
}
思考:index的值是0還是1
On class method invocation, any parameters are passed in consecutive local variables starting from local variable 0. On instance method invocation, local variable 0 is always used to pass a reference to the object on which the instance method is being invoked (this in the Java programming language). Any parameters are subsequently passed in consecutive local variables starting from local variable 1.
2.3.3.4 The pc Register(程式計數器)
我們都知道一個JVM行程中有多個執行緒在執行,而執行緒中的內容是否能夠擁有執行權,是根據CPU調度來的,
假如執行緒A正在執行到某個地方,突然失去了CPU的執行權,切換到執行緒B了,然后當執行緒A再獲得CPU執行權的時候,怎么能繼續執行呢?這就是需要在執行緒中維護一個變數,記錄執行緒執行到的位置,
如果執行緒正在執行Java方法,則計數器記錄的是正在執行的虛擬機位元組碼指令的地址;
如果正在執行的是Native方法,則這個計數器為空,
The Java Virtual Machine can support many threads of execution at once (JLS §17). Each Java Virtual Machine thread has its own pc (program counter) register. At any point, each Java Virtual Machine thread is executing the code of a single method, namely the current method (§2.6) for that thread. If that method is not native, the pc register contains the address of the Java Virtual Machine instruction currently being executed. If the method currently being executed by the thread is native, the value of the Java Virtual Machine's pc register is undefined. The Java Virtual Machine's pc register is wide enough to hold a returnAddress or a native pointer on the specific platform.
2.3.3.5 Native Method Stacks(本地方法堆疊)
如果當前執行緒執行的方法是Native型別的,這些方法就會在本地方法堆疊中執行,
那如果在Java方法執行的時候呼叫native的方法呢?
enough to hold a returnAddress or a native pointer on the specific platform.
#### 2.3.3.5 Native Method Stacks(本地方法堆疊)
如果當前執行緒執行的方法是Native型別的,這些方法就會在本地方法堆疊中執行,
那如果在Java方法執行的時候呼叫native的方法呢?

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/294075.html
標籤:其他
上一篇:Nexus 私有倉庫
