JVM越來越是Java面試中的
重頭戲,今天來總結一下JVM運行時資料區的相關內容,
文章目錄
- JVM運行時資料區
- JVM運行時資料區內部結構
- 程式計數器(PC暫存器)
- 程式計數器的介紹
- PC暫存器的實踐
- 兩個常見的問題
- 使用PC暫存器存盤位元組碼指令地址有什么用?
- PC暫存器為什么要設定為執行緒私有的?
- 拓展
- 虛擬機堆疊
- 記憶體中的堆疊和堆
- 堆疊的存盤單位
- 堆疊幀的內部結構
- 區域變數表
- **Demo:位元組碼中方法內部結構剖析**
- Demo:關于Slot的理解
- 運算元堆疊
- 運算元堆疊和區域變數表代碼追蹤
- 堆疊頂快取技術
- 動態鏈接
- 方法的呼叫:決議和分派
- 方法回傳地址(Return Address)
- 一些附加資訊
- 堆疊相關面試題
- 1.舉例說明堆疊溢位的情況(StackOverflowError)
- 2.調整堆疊大小,就能保證不出現溢位嗎?
- 3.分配的堆疊記憶體越大越好嗎?
- 4.垃圾回收是否會涉及到虛擬機堆疊?
- 5.方法中定義的區域變數是否執行緒安全嗎?
- 本地方法堆疊
- 對于本地介面的理解
- 本地方法堆疊
JVM運行時資料區
JVM運行時資料區內部結構

JVM內部布局規定了Java在運行程序中記憶體申請、分配、管理的策略,保證了JVM的高效穩定運行,不同的JVM對于記憶體的劃分方式和管理機制存在著部分差異,
阿里對于JVM記憶體區域的劃分

程式計數器(PC暫存器)
程式計數器的介紹
JVM中的程式計數暫存器(Program Counter Register)中,Register的命名源于CPU的暫存器,暫存器存盤相關的現場資訊,CPU只有把資料裝載到暫存器才能夠運行,
這里,并非是廣義上所指的物理暫存器,貨物將其翻譯為PC計數器(指令計數器)會更加貼切,JVM中的PC暫存器是對物理PC暫存器的一種抽象模擬(程式計數器也可以簡單的理解為行號指示器),
我們的JVM本身就是一種軟體層面的虛擬機,
作用:
PC暫存器用來存盤指向下一條指令的地址,就是即將要執行的指令代碼,由執行引擎讀取下一條指令,

特點:
- 程式計數器是一片很小的記憶體空間,也是運行速度最快的存盤區域
- 在JVM規范中,每個執行緒都有它自己的程式計數器,是執行緒私有的,宣告周期和該執行緒的生命周期一致,
- 任何時間,一個執行緒都只有一個方法正在執行,也就是所謂的
當前方法,程式計數器會存盤當前執行緒正在執行的Java方法的JVM指令地址,如果正在執行的方法是一個native方法,那么程式計數器則是未指定值(undefind) - 它是控制流的指示器,分支、回圈、跳轉、例外處理、執行緒恢復等基礎功能都需要依賴這個計數器完成
- 可以和集合中的迭代器的想法是類似的,迭代器指示的是當前遍歷集合中的某一個元素,而程式計數器指的是當前執行緒正在執行方法的下一條需要執行的指令,
- 程式計數器是JVM規范中規定的唯一一個不會發生OOM(OutOfMemoryError)的區域,
我們在研究JVM記憶體區域的時候,需要關注的點就試GC和OOM
| 區域 | GC | OOM |
|---|---|---|
| 程式計數器 | 沒有 | 沒有 |
| 堆 | 有 | 有 |
| 堆疊 | 不考慮GC | 有 |
| 本地方法堆疊 | 不考慮GC | 有 |
| 方法區 | 有 | 有 |
PC暫存器的實踐
- 為了方便,可以在idea中安裝插件jclasslib


兩個常見的問題
使用PC暫存器存盤位元組碼指令地址有什么用?
為什么使用PC暫存器記錄當前執行緒的執行地址?
因為CPU需要不停的切換各個執行緒,那么在切換回來之后,就需要知道接著從哪開始繼續執行.
JVM的位元組碼解釋器就需要通過改變PC暫存器的值來明確下一條應該執行什么樣的位元組碼指令,
PC暫存器為什么要設定為執行緒私有的?
PC暫存器是記錄當前正在執行方法的下一條即將執行的指令的行號,如果是執行緒之間共享的,那么在CPU切換執行緒時,PC寄存區所記錄的行號就可以被修改,當再次切換回原來的執行緒時,指示的行號可能不是原來需要執行的下一條指令的行號,這時就發生了錯誤,因為需要給每個執行緒都單獨的記錄當前的地址值,
為了能夠準確記錄各個執行緒正在執行的當前位元組碼的指令地址,最好的辦法就是為每個執行緒都分配一個PC暫存器,
拓展
在實際上,我們電腦上都有多個CPU,每個CPU有多個核,我們從宏觀上我們看到程式好像是并行的執行(真正的同時執行),其實微觀上,程式可能是由于CPU的高速的切換,然后在固定的時間片內執行程式,是并發的操作,
虛擬機堆疊
由于跨平臺的設計,Java的指令是根據堆疊來設計的,
為什么說由于跨平臺的設計,Java的指令是根據堆疊來設計的?
因為Java要實作跨平臺的設計(不同平臺CPU的架構不同),因此JVM中的指令是采用零指令的,也就是說只取最上層的指令,因此用堆疊來實作很契合,
優點是:跨平臺,指令集小,編譯器容易實作,缺點是性能下降,實作同樣的功能需要更多的指令
記憶體中的堆疊和堆
堆疊是運行時的單位,而堆是存盤時的單位
堆疊解決程式的運行問題,即程式如何執行,或者說如何處理資料,堆解決的是資料存盤的問題,即資料怎么放,放在哪?
Java虛擬機堆疊是什么?
Java虛擬機堆疊,早期也叫Java堆疊,每個執行緒在創建時都會創建一個虛擬機堆疊,存盤的是一個個堆疊幀,對應著一次次的Java方法呼叫
- 執行緒私有
生命周期
生命周期和執行緒一致
作用
主管Java程式的運行,它保存區域變數(8種基本資料型別,參考資料型別的地址)、部分結果,并參與方法的呼叫和回傳,
堆疊的特點
- 堆疊是一種快速有效的分配存盤方式,訪問速度僅次于程式計數器
- JVM直接對虛擬機堆疊的操作
- 每個方法執行,伴隨著進堆疊(入堆疊,壓堆疊)
- 方法執行結束后的出堆疊
- 對于堆疊來說不存在垃圾回收問題
- 在JVM中,是可能存在OOM問題的,

也就是對于JVM中,我們只操作堆疊頂的元素(堆疊幀),因此是零指令,跨平臺,
堆疊中可能出現的例外
JVM虛擬機規范中規定允許Java堆疊的大小是動態的或者固定不變
- 如果采用大小規定的Java虛擬機堆疊,那每一個Java虛擬機堆疊容量可以在執行緒創建的時候獨立選定.如果堆疊執行緒請求分配的堆疊的容量大于Java虛擬機堆疊允許的最大容量,Java虛擬機會拋出
StackOverflowError - 如果Java虛擬機可以動態擴展,并且在嘗試擴展的時候無法申請到足夠的記憶體,或者在創建新的執行緒時沒有足夠的記憶體去創建新的虛擬機堆疊,那么Java虛擬機會拋出一個
OutofMemoryError
設定堆疊的大小
前面說倒JVM虛擬機堆疊是允許設定固定大小的,
可以使用引數 -Xss (size) 選項來設定虛擬機堆疊的最大堆疊空間,堆疊的大小直接決定了函式呼叫的最大可達深度
注意設定的size默認是以byte(位元組為單位的),如果要設定為kb,那么就在size后面加上K或者k,如果要設定為Mb,那么就在size后面加上m或者M,如果要設定為GB,那么就在size后面加上G或者g
在Idea中設定堆疊的大小


堆疊的存盤單位
堆疊中存盤什么?
- 每一個執行緒都有自己的堆疊,堆疊中的資料都是以
堆疊幀的方式存在, - 在這個執行緒上
正在執行的每個方法都對應著一個堆疊幀, - 堆疊幀是一個記憶體區塊,是一個資料集,維系著方法執行程序中的各種資料資訊,
堆疊運行原理
- JVM直接對java堆疊的操作只有兩個,就是對堆疊幀的
壓堆疊和出堆疊,遵循"先進后出/后進先出"原則, - 在一潭訓動執行緒中,一個時間點上,只會有一個活動的堆疊幀,即只要當前正在執行的方法的堆疊幀(堆疊頂堆疊幀)是有效的,這個堆疊幀被稱為
當前堆疊幀(Current Frame),與當前堆疊幀相對應的方法就是當前方法(Current Method),定義這個方法的類就是當前類(Current Class), - 執行引擎運行的所有位元組碼指令只針對當前堆疊幀進行操作,
- 如果在該方法中呼叫了其他方法,對應的新的堆疊幀會被創建出來,放在堆疊的頂端,稱為新的當前幀,

- 不同執行緒中所包含的堆疊幀是不允許存在相互參考的,即不可能在一個堆疊幀中參考另一個執行緒的堆疊幀,
- 如果當前方法呼叫了其他方法,方法回傳之際,當前堆疊幀會傳回此方法的執行結果給前一個堆疊幀,接著虛擬機會丟棄當前堆疊幀,使得前一個堆疊幀重新成為當前堆疊幀,
- Java方法有兩種回傳函式的方式,
一種是正常的函式回傳,使用return指令;另一種是拋出例外(這里的拋出例外指的是我們對于例外拋出,但是在當前方法不進行處理),不管使用那種方式,都會導致堆疊幀被彈出,
堆疊幀的內部結構
區域變數表運算元堆疊(或運算式堆疊)- 動態鏈接(或指向運行時常量池的參考)
- 方法回傳地址(或方法正常退出或例外退出的定義)
- 一些附加資訊
區域變數表
- 區域變數表也稱為區域變數陣列或本地變數表
定義為一個數字陣列,主要用于存盤方法引數和定義在方法體內的區域變數這些資料型別包括各類基本資料型別、物件參考(reference),以及returnAddress型別- 由于區域變數表是建立在執行緒的堆疊上,是執行緒私有的,因此
不存在資料安全問題 區域變數表所需的容量大小是在編譯期就確定下來的,并保存在方法的code屬性的maximum local variables資料項中,在方法運行期間是不會改變區域變數表的大小的,方法嵌套呼叫的次數由堆疊的大小決定,一般來說堆疊越大,方法嵌套呼叫次數越多,對于一個函式而言,它的引數和區域變數越多,使得區域變數表膨脹,它的堆疊幀就越大,以滿足方法呼叫所需傳遞的資訊增大的需求,進而函式呼叫就會占用更多的堆疊空間,導致其嵌套呼叫次數就會減少,區域變數表中的變數只在當前方法呼叫中有效,在方法執行時虛擬機通過使用區域變數表完成引數值到引數變數串列的傳遞程序,當方法呼叫結束后,隨著方法堆疊幀的銷毀,區域變數表也會隨之銷毀,
Demo:位元組碼中方法內部結構剖析
- 可以使用idea自帶的反編譯的命令: javap -v LocalVariablesTest.class
- 也可以使用jclasslib插件快捷的剖析內部結構


關于Slot的理解
- 引數值的存放總在區域變數表(區域變數陣列)的index0開始,到陣列長度-1的索引結束
- 區域變數表,
最基本的存盤單元是Slot(變數槽) - 區域變數表中存放編譯期可知的各種基本資料型別(8種),參考資料型別(reference),returnAddress型別的變數
- 在區域變數表中,32位以內的型別只占用一個Slot(包括returnAddress型別),64位的型別(long和double)占用兩個Slot
- byte、shoot、char在存盤前輩轉換為int,boolean也被轉換為int,0 寶石false,非0 表示true
- long和double則占據兩個Slot
- JVM會為區域變數表中的每一個Slot都分配一個訪問索引,通過這個索引就能夠訪問到區域變數表中指定的區域變數值
- 如果需要訪問的區域變數中的一個64bit的區域變數值是,只需要使用前一個索引即可,
- 如果當前幀時由構造方法或者實體方法創建的,那么該物件參考his將會存放在index為0 的slot處,其余的引數按照引數表順序繼續排列
Demo:關于Slot的理解

- 要注意不同的資料型別占據的Slot的槽位數量不同
- 堆疊幀中區域變數表中的槽位是可以重用的,如果一個區域變數過了其作用域,那么在其作用域之后宣告的新的區域變數就很有可能會復用過期區域變數的槽位,從而達到節省資源的目的,

拓展:成員變數和區域變數的區別
通過上面的學習,我們知道了在區域變數表中存盤的是在方法中宣告的區域變數,
變數的分類:
按照資料型別分為:①基本資料型別變數②參考資料型別變數
按照在類中宣告的位置:①用戶變數:類變數,實體變數②區域變數
使用的區別:
- 類變數:在linking的prepare階段,會對類變數默認賦值---->initial階段會對其顯式賦值
- 實體變數:隨著物件的創建,也會在堆空間中分配實體變數空間,并進行默認賦值
- 區域變數:是在方法執行時,會在區域變數表中分配區域變數的空間,并顯式賦值
注意:區域變數在使用之前必須進行顯式賦值
運算元堆疊
運算元堆疊首先是一個堆疊的特點,也就是先進后出(后進先出)的特點
- 每一個堆疊幀除了有一個區域變數表以外,還有一個
后進先出的運算元堆疊,也稱為運算式堆疊 運算元堆疊,在方法執行的程序中,往堆疊中寫入資料或提取資料,即入堆疊(push)或出堆疊(pop)- 某些位元組碼指令將值壓入運算元堆疊,另外一些操作指令將運算元取出操作后再壓入堆疊內
- 比如執行復制、交換、求和等操作,
- 運算元堆疊,
主要用于保存計算程序中的中間結果,同時作為計算程序中變數的臨時存盤空間 - 運算元堆疊是JVM執行引擎的一個作業區域,當一個方法剛開始執行的時候,一個新的堆疊幀就被創建出來,
這個方法的運算元堆疊的空的 - 每一個運算元堆疊都有一個明確的堆疊深度用于存盤數值,其所需的最大深度在編譯期就確定了,存盤在Code屬性中,為max——stack的值,并且該值在方法執行時不能修改,
- 堆疊中的資料結構可以是Java中任意的資料型別
- 32bit的型別占用一個堆疊的深度
- 64bit的型別占用兩個堆疊的深度
- 運算元堆疊雖然是用陣列的方式實作的,但是不能采用索引隨機訪問的方式,而只能采用標準的入堆疊和出堆疊操作來完成資料訪問,
運算元堆疊和區域變數表代碼追蹤

堆疊頂快取技術
前面有提到:因為JVM采用的是堆疊的方式來實作指令的操作,但是伴隨而來的就是完成同一個操作需要的指令更多,需要頻繁的入堆疊和出堆疊,而入堆疊和出堆疊是消耗性能的,
堆疊頂快取技術的思想就是:將出堆疊的所有運算元都快取在CPU的暫存器中,這樣避免了多次的出堆疊和入堆疊的性能消耗,這個技術可能在未來能夠實作,
動態鏈接
- 每一個堆疊幀內部都包含一個指向
運行時常量池中該堆疊幀所屬方法的參考,包含這個參考的目的就是為了支持當前方法的代碼能夠實作動態鏈接,比如invokedynamic指令, - 在Java源檔案被編譯到位元組碼檔案中時,所以的變數和方法參考都作為符號參考保存在class檔案的常量池中,比如:描述一個方法呼叫了另外的其他方法時,就是通過常量池中指向方法的符號參考來表示的,那么
動態鏈接的作用就是為了將這些符號參考轉換為呼叫方法的直接參考
理解為什么要有動態鏈接來指向地址,而不是直接存物件?
- 因為堆疊的記憶體是有限的,如果要在堆疊中直接存入大量的物件,那么對于堆疊空間的消耗是比較大的,
- 堆疊是執行緒私有的,而很多物件和一些常量是需要執行緒之間共享的,如果在堆疊中直接存盤那么就不能達到執行緒共享的目的,

方法的呼叫:決議和分派
在JVM中,將符號參考轉換為呼叫方法的直接參考與方法的系結機制有關,
- 靜態鏈接
當一個位元組碼檔案被裝載進JVM內部時,如果被呼叫的目標方法在編譯期可知,且運行期保持不變,這種情況下將呼叫方法的符號參考轉換為直接參考的程序稱之為靜態鏈接,
- 動態鏈接
如果被呼叫的方法在編譯期無法被確定下來,也就是說,只能夠在程式運行期將呼叫方法的符號參考轉換為直接參考,由于這種參考轉換程序具備動態性,因此也被稱之為動態鏈接,
對應著靜態鏈接和動態鏈接就有早期系結和晚期系結,
- 早期系結指的是在編譯期就能確定且無法更改
- 晚期系結指的是在運行時才能確定
對應著,也就有虛方法和非虛方法
方法的呼叫:虛方法和非虛方法
虛擬機中提供了一下幾條方法呼叫指令:
普通呼叫指令:
- invokestatic:呼叫靜態方法,決議階段確定唯一方法版本
- invokespecial:呼叫< init >方法、私有及父類方法,決議階段確定唯一版本
- 注意這里呼叫要顯式的呼叫,比如呼叫父類的方法:super.myMethod();
- invokevirtual:呼叫所有虛方法
- invokeinterface:呼叫介面方法
動態呼叫指令:
- invokedynamic:動態決議出需要呼叫的方法,然后執行
方法回傳地址(Return Address)
- 存放呼叫該方法的pc暫存器的值
- 一個方法的結束,有兩種方式:
- 正常執行完成
- 出現未處理的例外,非正常退出
- 無論通過哪種方式退出,在方法退出后都回傳到該方法呼叫的位置,方法正常退出時,
呼叫者的pc計數器的值作為方法的回傳地址,即呼叫該方法的指令的下一條指令的地址,而通過例外退出的,回傳地址要通過例外表來確定,堆疊幀一般不保存這部分的資訊,
本質上,方法的退出就是當前堆疊幀出堆疊的程序,此時,需要恢復上層方法的區域變數表、運算元堆疊、將回傳值壓入呼叫者堆疊幀中的運算元堆疊、設定暫存器值等,讓呼叫者方法繼續執行下去,
正常完成出口和例外完成出口的區別在于:通過例外完成出口退出的不會給他的上層呼叫者產生任何的回傳值,
當一個方法開始執行后只有兩種方式可以退出這個方法:
- 執行引擎遇到任意一個方法回傳的位元組碼指令(return),會有回傳值傳遞給上層的方法呼叫者,簡稱
正常完成出口,- 一個方法在正常呼叫完成之后究竟需要使用哪一個回傳指令還需要根據方法回傳值的實際資料型別而定,
- 在位元組碼指令中,回傳指令包含ireturn(當回傳值是boolean、byte、char、short和int型別時使用)、lreturn、freturn、deturn以及areturn,另外還有一個return指令供宣告為void的方法、實體初始化方法、類和介面的初始化方法使用,
- 在方法執行的程序中遇到了例外(Expection),并且這個例外沒有在方法內進行處理,也就是只要在本方法的例外表中沒有搜索到匹配的例外處理器,就會導致方法退出,簡稱
例外完成出口
方法執行程序中拋出例外時的例外處理,存盤在一個例外處理表中,方便在發生例外的時候找到處理例外的代碼,
一些附加資訊

堆疊幀中還允許攜帶與Java虛擬機實作相關的一些附加資訊,例如:對程式除錯提供支持的資訊,(不一定有,可能有也可能沒有),
堆疊相關面試題
1.舉例說明堆疊溢位的情況(StackOverflowError)
該題討論的是堆疊溢位,堆疊溢位導致的原因就是:一般情況下,堆疊是用陣列實作的,那么在編譯時期就確定了大小,那么就可能出現堆疊溢位的問題,導致的原因可能有:無限的遞回呼叫(無線的遞回呼叫會創建大量的堆疊幀,從而撐爆堆疊記憶體),
追問:當發生堆疊溢位時,我們怎么解決?
- 檢查程式的邏輯,是否有無限遞回,或者死回圈,
- 也可以使用-Xss size來設定堆疊的大小,
2.調整堆疊大小,就能保證不出現溢位嗎?
不能保證,
調整堆疊空間的大小,能讓堆疊空間中能存盤更多的堆疊幀,但是還是不能保證不出現堆疊溢位,因為堆疊幀的數量可能是不確定的,可能是無限遞回呼叫或者死回圈,
調整堆疊空間的大小,只能保證出現OOM的時間變晚一點,
3.分配的堆疊記憶體越大越好嗎?
不是,JVM中堆疊的記憶體越大意味著java程式中單個執行緒的記憶體過大,這樣會影響整個java程式的程式并發數,
4.垃圾回收是否會涉及到虛擬機堆疊?
垃圾回收不能回收站的記憶體空間,
為什么不使用垃圾回收來回收虛擬機堆疊的記憶體,因為我們虛擬機堆疊是一個堆疊結構,在該結構中的資料都被認為是正在使用的資料,當一個方法呼叫結束時,那么就會自動回收,不需要垃圾回收執行緒的額外監控,
5.方法中定義的區域變數是否執行緒安全嗎?
不一定是安全的,
堆疊中的區域變數表中存盤的資料可能有兩種,基本資料型別和參考資料型別,對于基本資料型別而言,如果是該方法是單執行緒操作它,那么就是執行緒安全的,如果是多執行緒操作也可能不安全,如果是參考資料型別,因為參考資料型別存盤的是一個地址的參考,而該地址的參考可能同時被多個執行緒所操作,因此也是執行緒不安全的,
特別要注意在
方法引數串列中的區域變數、回傳值中的區域變數是可能發生區域變數的參考逃逸,
擼代碼
//執行緒不安全
public staic StringBuilder method1(){
//注意這里使用的一個本身執行緒就不安全的字串,如果使用執行緒安全的字串,那么在本身對于方法的操作都加了鎖,都會是執行緒安全的
StringBuilder str = new StringBuilder();
str.append("1");
str.append("2");
return str;
}
- 本身方法中操作的字串不是一個執行緒安全的字串
- 回傳的不是字串本身(也就是該字串的地址參考),因此是可能造成執行緒不安全問題的
//執行緒安全
public staic String method1(){
//注意這里使用的一個本身執行緒就不安全的字串,如果使用執行緒安全的字串,那么在本身對于方法的操作都加了鎖,都會是執行緒安全的
StringBuilder str = new StringBuilder();
str.append("1");
str.append("2");
return str.toString();
}
- 本身方法中操作的字串不是一個執行緒安全的字串
- 但是回傳的是該字串本身,而不是改字串的地址參考
- 回傳的是str的toString()方法,在toString()方法中其實是new了一個新的String,回傳的這個新的String物件是執行緒安全的,String用final修飾,也就是其不可改變,改變就會生成新的String,
注意甄別這兩個方法,
總結一下:
在方法中
- 如果一個區域變數是產生在內部,并在內部消亡的,那么它就是執行緒安全的,
- 如果一個區域變數不產生在內部或者不是在內部消亡的,那么它就不是執行緒安全的,
本地方法堆疊
再看一眼整體的結構圖:

對于本地介面的理解
本地方法:
簡單來講,一個
Native Method就是一個Java呼叫非Java代碼的介面,一個Native Method是這樣一個Java方法:該方法的實作是由非Java語言實作,比如C,本地介面的作用是融合不同的編程語言為Java所用,它的初衷是融合C/C++語言,
有本地方法堆疊和本地方法的原因:
- 與Java環境之外互動
- Java語言誕生之初,希望能C/C++有更多互動,讓更多人使用
- 發展后期,希望你和其他語言互動,更健壯
- 與作業系統互動
- 和作業系統的互動,作業系統多用C/C++語言撰寫的,使用本地方法就能實作Java和作業系統的互動,
- Sun‘s java
- Sun的解釋器是用C實作的,這使得它能喝普通的C一樣與外部互動,
本地方法堆疊
Java虛擬機堆疊是管理Java方法的呼叫,而本地方法堆疊用來管理本地方法的呼叫,
-
本地方法堆疊也是執行緒私有的,
-
允許被實作成固定或者是可動態擴展的記憶體大小(在記憶體溢位方面是相同的)
- 如果執行緒請求分配的堆疊容量大于本地方法堆疊的最大容量,俺么就會拋出StackOverflowError例外,
- 如果本地方法堆疊可以動態擴展,并且在嘗試擴展的時候無法申請到足夠的空間或者在創建新的執行緒時沒有足夠的空間,那么就會拋出OutOfMemoryError例外,
-
本地方法是用C語言實作的,
-
它的具體做法是在Native Method Stack中登記native方法,在Execution Engine執行時加載本地方法庫,
-
當某個執行緒呼叫一個本地方法時,它就進入了一個全新的并且不再受虛擬機限制的空間.它和虛擬機擁有同樣的權限- 本地方法可以通過本地方法介面來
訪問虛擬機內部的運行時資料區 - 它甚至可以使用本地處理器中的暫存器
- 直接從本地記憶體中的堆中分配任意的記憶體
Java方法的呼叫,而本地方法堆疊用來管理本地方法的呼叫`,
- 本地方法可以通過本地方法介面來
-
本地方法堆疊也是執行緒私有的,
-
允許被實作成固定或者是可動態擴展的記憶體大小(在記憶體溢位方面是相同的)
- 如果執行緒請求分配的堆疊容量大于本地方法堆疊的最大容量,俺么就會拋出StackOverflowError例外,
- 如果本地方法堆疊可以動態擴展,并且在嘗試擴展的時候無法申請到足夠的空間或者在創建新的執行緒時沒有足夠的空間,那么就會拋出OutOfMemoryError例外,
-
本地方法是用C語言實作的,
-
它的具體做法是在Native Method Stack中登記native方法,在Execution Engine執行時加載本地方法庫,
-
當某個執行緒呼叫一個本地方法時,它就進入了一個全新的并且不再受虛擬機限制的空間.它和虛擬機擁有同樣的權限- 本地方法可以通過本地方法介面來
訪問虛擬機內部的運行時資料區 - 它甚至可以使用本地處理器中的暫存器
- 直接從本地記憶體中的堆中分配任意的記憶體
- 本地方法可以通過本地方法介面來
-
HotSpot虛擬機中將虛擬機堆疊和本地方法堆疊合二為一,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/224842.html
標籤:其他
