JVM学习(七):运行时数据区(精讲)
目錄
一、運行時數據區概述
1.1 概述?
1.2 運行時數據區中的GC和OOM
二、程序計數器(PC寄存器,Program Counter Register)
2.1 介紹
2.2 作用?
2.3 特點?
2.4 使用案例
2.5 常見面試題
三、虛擬機棧(Java Virtual Machine Stack)
四、本地方法接口
4.1 本地方法(Native Method)
4.2?為什么要使用Native Method
4.3 現狀
五、本地方法棧(Native Method Stack)
5.1 本地方法棧的作用?
5.2 本地方法棧的特點?
六、堆(Heap)
七、方法區(Method Area)
八、總結?
一、運行時數據區概述
1.1 概述?
? ? ? ? 運行時數據區要講的是圖中粉紅區域的知識。?
? ? ? ? Java虛擬機定義了若干種程序運行期間會使用到的運行時數據區,其中有一些會隨著虛擬機啟動而創建,隨著虛擬機退出而銷毀,生命周期與JVM相同(也是多個線程共享的);另外一些則是與線程一一對應的,這些與線程對應的數據區域會隨著線程開始和結束而創建和銷毀,生命周期與線程相同(也是單個線程獨享的)。?
?????????粉色區域中,多個線程共享的模塊被我們標記為紅色,單個線程獨享的模塊被標記為灰色。
? ? ? ? 關于運行時數據區的細節,我們可以看阿里巴巴提供的細一點的圖:
? ? ? ? ?我們注意到,Java中有個類叫Runtime。每個JVM只有一個Runtime實例。即為運行時環境,相當于第一張圖內存結構的中間包裹著粉色內容的那個大框框。
?1.2 運行時數據區中的GC和OOM
| 堆 | √ | √ |
| 方法區 | √ | √ |
| 虛擬機棧 | √ | × |
| 本地方法棧 | √ | × |
| 程序計數器 | × | × |
二、程序計數器(PC寄存器,Program Counter Register)
2.1 介紹
?????????JVM中的程序計數寄存器(Program counter Register)中, Register的命名源于CPU的寄存器,寄存器存儲指令相關的現場信息。CPU只有把數據裝載到寄存器才能夠運行。
????????這里并非是廣義上所指的物理寄存器,或許將其翻譯為PC計數器(或指令計數器)會更加貼切(也稱為程序鉤子),并且也不容易引起一些不必要的誤會。JVM中的PC寄存器是對物理PC寄存器的一種抽象模擬。
2.2 作用?
????????PC寄存器用來存儲指向下一條指令的地址,也是即將要執行的指令代碼。由執行引擎讀取下一條指令。
? ? ? ? 可以理解為是一個游標,或者Java集合中迭代器一樣的作用。
?
2.3 特點?
- 它是一塊很小的內存空間,幾乎可以忽略不記。也是運行速度最快的存儲區域
- 在JVM規范中,每個線程都有它自己的程序計數器,是線程私有的,生命周期與線程的生命周期保持一致
- 任何時間一個線程都只有一個方法在執行,也就是所謂的當前方法。程序計數器會存儲當前線程正在執行的Java方法的JVM指令地址;或者,如果是在執行native方法,則是未指定值(undefned)?
- 它是程序控制流的指示器,分支、循環、跳轉、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成
- 字節碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令
- 它是唯一一個在Java虛擬機規范中沒有規定任何OutOtMemoryError情況的區域
2.4 使用案例
? ? ? ? 我們來直觀看看程序計數器的作用。
? ? ? ? 先編寫一段簡單的Java代碼:
public class PCRegisterTest {public static void main(String[] args) {int i = 10;int j = 20;int k = i + j;String s = "abc";System.out.println(i);System.out.println(k);} }? ? ? ? ?我們將其反編譯,看看它的字節碼
? ? ? ? ?紅色框框起來的部分就叫做指令地址(偏移地址),PC寄存器中存放的就是他們。
2.5 常見面試題
- 使用PC寄存器存儲字節碼指令地址有什么用呢?為什么使用PC寄存器記錄當前線程的執行地址呢?
????????因為CPU需要不停的切換各個線程,這時候切換回來以后,就得知道接著從哪開始繼續執行。JVM的字節碼解釋器就需要通過改變PC寄存器的值來明確下一條應該執行什么樣的字節碼指令。
- PC寄存器為什么會被設定為線程私有?
????????我們都知道所謂的多線程在一個特定的時間段內只會執行其中某一個線程的方法,CPU會不停地做任務切換,這樣必然導致經常中斷或恢復,如何保證分毫無差呢?為了能夠準確地記錄各個線程正在執行的當前字節碼指令地址,最好的辦法自然是為每一個線程都分配一個PC寄存器,這樣一來各個線程之間便可以進行獨立計算,從而不會出現相互千擾的情況。
????????由于CPU時間片輪限制,眾多線程在并發執行過程中,任何一個確定的時刻,一個處理器或者多核處理器中的一個內核,只會執行某個線程中的一條指令。這樣必然導致經常中斷或恢復,所以每個線程在創建后,都會產生自己的程序計數器和棧幀,程序計數器在各個線程之間互不影響。
三、虛擬機棧(Java Virtual Machine Stack)
? ? ? ? 要講的太多了,寫了16000多字,拆分出一篇文章專門來講:
????????JVM學習(八):運行時數據區——虛擬機棧(字節碼程度深入剖析)_玉面大蛟龍的博客
四、本地方法接口
? ? ? ? 這并不是運行時數據區里的內存結構,而是下圖中黃色部分:
4.1 本地方法(Native Method)
????????簡單地講,一個Native Method就是一個Java調用非Java代碼的接口。
????????一個Native Method是這樣一個Java方法:該方法的實現由非Java語言實現,比如C。這個特征并非Java所特有,很多其它的編程語言都有這一機制,比如在C++中,你可以用extern "C"告知C++編譯器去調用一個C的函數。
"A native method is a Java method whose implementation provided by non-java code . "
????????在定義一個native method時,并不提供實現體(有點像定義一個Java interface,但不是interface,也不是abstract method),因為其實現體是由非java語言在外面實現的。
????????本地接口的作用是融合不同的編程語言為Java所用,它的初衷是融合C/C++程序。
? ? ? ? 我們也可以自己寫一些本地方法:
public class IHaveNatives {public native void Native1(int x);public native static long Native2();private native synchronized float Native3(Object o);native void Native4(int[] ary) throws Exception;}?????????標識符native可以與所有其它的java標識符連用,但是abstract除外。
4.2?為什么要使用Native Method
????????Java使用起來非常方便,然而有些層次的任務用Java實現起來不容易,或者我們對程序的效率很在意時,問題就來了。
- 與Java環境外交互
????????有時Java應用需要與Java外面的環境交互,這是本地方法存在的主要原因。Java中存在需要與一些底層系統,如操作系統或某些硬件交換信息時的情況。本地方法正是這樣一種交流機制:它為我們提供了一個非常簡潔的接口,而且我們無需去了解Java應用之外的繁瑣的細節。
- 與操作系統交互
????????JVM支持著Java語言本身和運行時庫,他是Java程序賴以生存的平臺,它由一個解釋器(解釋字節碼)和一些連接到本地代碼的庫組成。然而不管怎么樣,他畢竟不是一個完整的系統,它經常依賴于一些底層系統的文持。這些底層系統常常是強大的操作系統。通過使用本地方法。我們得以用Java實現了jre與底層系統的交互,甚至JVM的一些部分就是用C寫的。還有,如果我們要使用一些Java語言本身沒有提供封裝的的操作系統的特性時,我們也需要使用本地方法。
- Sun 's Java
????????Sun的解釋器是用C實現的,這使得它能像一些普通的C一樣與外部交互。jre大部分是用Java實現的,它也通過一些本地方法與外界交互。例如:類 java.lang.Thread?的 setPriority()方法是用Java實現的,但是它實現調用的是該類里的本地方法 setPriority0()。這個本地方法是用C實現的,并被植入JVM內部,在windows 95 的平臺上,這個本地方法最終將調用win32 SetPriority() API。這個本地方法的具體實現由JVM直接提供,更多的情況是本地方法由外部的動態鏈接庫
(external dynamic link library)提供,然后被JVM調用。
4.3 現狀
????????目前該方法使用的越來越少了,除非是與硬件有關的應用。比如通過Java程序驅動打印機或者Java系統管理生產設備,在企業級應用中已經比較少見。因為現在的異構領域間的通信很發達,比如可以使用socket通信,也可以使用web service等等,不多做介紹。
五、本地方法棧(Native Method Stack)
5.1 本地方法棧的作用?
? ? ? ? 一句話就可以說清楚:Java虛擬機棧用于管理Java方法的調用,而本地方法棧用于管理本地方法的調用。
5.2 本地方法棧的特點?
- 本地方法棧,也是線程私有的
- 允許被實現成固定或者是可動態擴展的內存大小。(在內存溢出方面是相同的)
- 如果線程請求分配的棧容量超過本地方法棧允許的最大容量,Java虛擬機將會拋出一個StackOverflowError異常
- 如果本地方法??梢詣討B擴展,并且在嘗試擴展的時候無法申請到足夠的內存,或者在創建新的線程時沒有足夠的內存去創建對應的本地方法棧,那么Java虛擬機將會拋出一個OutOfMemoryError異常
- 本地方法是使用C語言實現的
- 它的具體做法是Native Method Stack中登記native方法,在Execution Engine執行時加載本地方法庫
- 當某個線程調用一個本地方法時,它就進入了一個全新的并且不再受虛擬機限制的世界。它和虛擬機擁有同樣的權限
- 本地方法可以通過本地方法接口來訪問虛擬機內部的運行時數據區
- 它甚至可以直接使用本地處理器中的寄存器
- 也可以直接從本地內存的堆中分配任意數量的內存。
- 并不是所有的JVM都支持本地方法。因為Java虛擬機規范并沒有明確要求本地方法棧的使用語言、具體實現方式、數據結構等。如果JVM產品不打算支持native方法,也可以無需實現本地方法棧。
- 在Hotspot JVM中,直接將本地方法棧和虛擬機棧合二為一
六、堆(Heap)
? ? ? ? 詳見我的文章:JVM學習(九):堆(萬字剖析)_玉面大蛟龍的博客-CSDN博客?
七、方法區(Method Area)
? ? ? ? 詳見我的文章:JVM學習(十):方法區_玉面大蛟龍的博客-CSDN博客
八、總結?
總結
以上是生活随笔為你收集整理的JVM学习(七):运行时数据区(精讲)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我们购买台灯时保护眼睛什么光的灯最好呢?
- 下一篇: 面试必备技能,springsecurit