1. 程式人生 > >虛擬機器棧-----執行緒中虛擬機器棧

虛擬機器棧-----執行緒中虛擬機器棧

虛擬機器棧

棧幀

1.1定義

棧幀(stack frame)是用於支援虛擬機器進行方法呼叫和方法執行的資料結構,它是虛擬機器執行時資料區中的虛擬機器棧的棧元素。棧幀儲存了方法的區域性變量表、運算元棧、動態連線和方法返回地址等資訊。
每一個方法從呼叫開始到執行完成的過程,就對應著一個棧幀在虛擬機器棧裡面從入棧到出棧的過程。
對於執行引擎來說,活動執行緒中,只有棧頂的棧幀是有效的,稱為當前棧幀,這個棧幀所關聯的方法稱為當前方法。執行引擎所執行的所有位元組碼指令都只針對當前棧幀進行操作。

1.區域性變量表

區域性變量表是一組變數值儲存空間,用於存放方法引數和方法內部定義的區域性變數。在Java程式被編譯成Class檔案時,就在方法的Code屬性的max_locals資料項中確定了該方法所需要分配的
最大區域性變量表的容量。
區域性變量表的容量以變數槽(Slot)為最小單位

,32位虛擬機器中一個Slot可以存放一個32位以內的資料型別(boolean、byte、char、short、int、float、reference和returnAddress八種)。
reference型別虛擬機器規範沒有明確說明它的長度,但一般來說,虛擬機器實現至少都應當能從此引用中直接或者間接地查詢到物件在Java堆中的起始地址索引和方法區中的物件型別資料。
returnAddress型別是為位元組碼指令jsr、jsr_w和ret服務的,它指向了一條位元組碼指令的地址。
虛擬機器是使用區域性變量表完成引數值到引數變數列表的傳遞過程的,如果是例項方法(非static),那麼區域性變量表的第0位索引的Slot預設是用於傳遞方法所屬物件例項的引用,在方法中通過this訪問。
Slot是可以重用的,當Slot中的變數超出了作用域
,那麼下一次分配Slot的時候,將會覆蓋原來的資料。Slot對物件的引用會影響GC(要是被引用,將不會被回收)。
系統不會為區域性變數賦予初始值(例項變數和類變數都會被賦予初始值)。也就是說不存在類變數那樣的準備階段。

2.運算元棧

Java虛擬機器的解釋執行引擎被稱為”基於棧的執行引擎”,其中所指的棧就是指-運算元棧。
運算元棧也常被稱為操作棧

和區域性變數區一樣,運算元棧也是被組織成一個以字長為單位的陣列。但是和前者不同的是,它不是通過索引來訪問,而是通過標準的棧操作—壓棧和出棧—來訪問的。比如,如果某個指令把一個值壓入到運算元棧中,稍後另一個指令就可以彈出這個值來使用。

  1. 棧幀剛建立使,運算元棧為空,執行方法操作時,運算元棧用於存放JVM從區域性變量表複製的常量或者變數,提供提取,及結果入棧,也用於存放呼叫方法需要的引數及接受方法返回的結果。
  2. 運算元棧可以存放一個jvm中定義的任意資料型別的值。
  3. 在任意時刻,運算元棧都一個固定的棧深度。

虛擬機器在運算元棧中儲存資料的方式和在區域性變數區中是一樣的:如int、long、float、double、reference和returnType的儲存。對於byte、short以及char型別的值在壓入到運算元棧之前,也會被轉換為int。
虛擬機器把運算元棧作為它的工作區——大多數指令都要從這裡彈出資料,執行運算,然後把結果壓回運算元棧。

3.動態連結

3.1 預備知識


符號引用與直接引用
符號引用就是字串,這個字串包含足夠的資訊,以供實際使用時可以找到相應的位置。你比如說某個方法的符號引用,如:“java/io/PrintStream.println:(Ljava/lang/String;)V”。裡面有類的資訊,方法名,方法引數等資訊。當第一次執行時,要根據字串的內容,到該類的方法表中搜索這個方法。執行一次之後,符號引用會被替換為直接引用,下次就不用搜索了。
直接引用就是偏移量,通過偏移量虛擬機器可以直接在該類的記憶體區域中找到方法位元組碼的起始位置。^_^!當然R大說的更正確。

3.2動態連結

什麼是動態連結、它有什麼用?
如上所述,在Class檔案中的常量池持中存有大量的符號引用。位元組碼中的方法呼叫指令就以常量池中指向方法的符號引用作為引數。這些符號引用一部分在類的載入階段(解析)或第一次使用的時候就轉化為了直接引用(指向資料所存地址的指標或控制代碼等),這種轉化稱為靜態連結。而相反的,另一部分在執行期間轉化為直接引用,就稱為動態連結。
與那些在編譯時進行連結的語言不同,Java型別的載入和連結過程都是在執行的時候進行的,這樣雖然在類載入的時候稍微增加一些效能開銷,但是卻能為Java應用程式提供高度的靈活性,Java中天生可以動態擴充套件的語言特性就是依賴動態載入和動態連結這個特點實現的。
動態擴充套件就是在執行期可以動態修改位元組碼,也就是反射機制cglib,有興趣的朋友可以查一下

3.3動態連結

每個棧幀都包含一個指向執行時常量池中該棧幀所屬方法的引用,持有這個引用是為了支援方法呼叫過程中的動態連線。Class檔案的常量池中存在有大量的符號引用,位元組碼中的方法呼叫指令就以常量池中指向方法的符號引用為引數。這些符號引用,一部分會在類載入階段或第一次使用的時候轉化為直接引用(如final、static域等),稱為靜態解析,另一部分將在每一次的執行期間轉化為直接引用,這部分稱為動態連線。

4.方法返回地址

當一個方法被執行後,有兩種方式退出該方法:執行引擎遇到了任意一個方法返回的位元組碼指令或遇到了異常,並且該異常沒有在方法體內得到處理。無論採用何種退出方式,在方法退出之後,都需要返回到方法被呼叫的位置,程式才能繼續執行。方法返回時可能需要在棧幀中儲存一些資訊,用來幫助恢復它的上層方法的執行狀態。一般來說,方法正常退出時,呼叫者的PC計數器的值就可以作為返回地址,棧幀中很可能儲存了這個計數器值,而方法異常退出時,返回地址是要通過異常處理器來確定的,棧幀中一般不會儲存這部分資訊。
方法退出的過程實際上等同於把當前棧幀出棧,因此退出時可能執行的操作有:恢復上層方法的區域性變量表和運算元棧,如果有返回值,則把它壓入呼叫者棧幀的運算元棧中,調整PC計數器的值以指向方法呼叫指令後面的一條指令

相關推薦

虛擬機器-----執行虛擬機器

虛擬機器棧 棧幀 1.1定義 棧幀(stack frame)是用於支援虛擬機器進行方法呼叫和方法執行的資料結構,它是虛擬機器執行時資料區中的虛擬機器棧的棧元素。棧幀儲存了方法的區域性變量表、運算元棧、動態連線和方法返回地址等資訊。 每

【Java虛擬機器執行安全與鎖優化

執行緒安全與鎖優化 絕對執行緒安全 相對執行緒安全 執行緒安全的實現方式 互斥同步 非阻塞同步 鎖優化 參考 絕對執行緒安全 當多個執行緒訪問一個物件時,如果不用考慮這些執行緒在執行時環境

java虛擬機器執行安全的簡單理解

java虛擬機器多執行緒安全及鎖優化 執行緒安全問題的產生 多執行緒技術的引入產生啦執行緒安全性問題:當多個執行緒操作共享的資料時,如果A執行緒對共享的資料做出改變時B執行緒也要操作共享的資料,就有可能發生執行緒執行錯誤,產生錯誤的結果. 執行緒安全按安全程度來分五級

Linux 的各種:程序 執行 核心 中斷

棧是什麼?棧有什麼作用? 首先,棧 (stack) 是一種串列形式的 資料結構。這種資料結構的特點是 後入先出 (LIFO, Last In First Out),資料只能在串列的一端 (稱為:棧頂 top) 進行 推入 (push) 和 彈出 (pop) 操作。根據

Java多執行Synchronized簡介和Static Synchronized的區別

在進行Java開發時,多執行緒的開發是經常會使用的。首先會問一個小問題啊,在Java中有幾種方法可以建立一個執行緒? 我給的答案是3種。(如果還有其他的請留言告訴我哈。) 1、建立直接繼承自Thread類建立執行緒子類。   步驟如下:a 定義一個子類,同時

java 執行的 wait()和sleep()

wait() 方法是寫在java.lang.Object類中的 (ps: notify()  notifyAll()也是在Object中定義的) wait()原始碼註釋: Causes the current thread to wait until either a

Android執行模型--在子執行更新UI

       Android是支援多執行緒的。主執行緒也稱UI執行緒,子執行緒也稱工作執行緒。一般耗時操作在子執行緒中進行,更新UI操作在主執行緒中進行。在主執行緒中執行耗時操作容易發生ANR錯誤,即應用程式無響應。而Android中又規定只有建立UI的執行緒

執行的佇列不一定需要執行安全

兩個執行緒,主執行緒中update update(){   while(queue.count >0){     //process....     queue.pop()   } }   子執行緒中: queue.enqueue(data)   這樣做是沒有問

junit測試和main方法多執行遇到的問題

利用Junit測試多執行緒時經常遇到任務執行不完就會停止,下面是我的任務執行緒類: package timerTest; import java.io.BufferedReader; import java.io.BufferedWriter; import java.i

Android面試:主執行的Looper.loop()一直無限迴圈為什麼不會造成ANR?(轉)

  引子: 正如我們所知,在android中如果主執行緒中進行耗時操作會引發ANR(Application Not Responding)異常。 造成ANR的原因一般有兩種: 只有當應用程式的UI執行緒響應超時才會引起ANR,超時產生原因一般有兩種 1. 當前的事件沒有機會

python執行join和和setDaemon

join([timeout]) 主執行緒A中,建立子執行緒B,B呼叫join函式會使得主執行緒阻塞,直到子執行緒執行結束或超時。引數timeout是一個數值型別,用來表示超時時間,如果未提供該引數,那麼主調執行緒將一直阻塞直到子執行緒結束。 注意:必須在start() 方法呼叫之後設

Android主執行向子執行傳送資訊

主要用到了Handler類,Looper類和Message類 先介紹下這幾個類 Looper類,是用來為一個執行緒開啟一個訊息佇列,預設情況下Android下新開啟的執行緒沒有開啟訊息佇列的,除了主執行緒外,主執行緒系統會預設為其開啟一個訊息佇列;looper是通過MessageQueu

UncaughtExceptionHandler處理執行執行時異常

執行緒在執行單元中不允許丟擲checked異常,而且執行緒執行在自己的上下文中,派生它的執行緒無法直接獲得它執行中出現的異常資訊。對此,Java為我們提供了UncaughtExceptionHandler介面,當執行緒在執行過程中出現異常時,會回撥UncaughtExceptionHan

曲速未來 警惕:新的網路釣魚活動將Ursnif放入對話執行

    區塊鏈安全諮詢公司 曲速未來 訊息:於今年9月發現的一項新的網路釣魚活動顯示,運營商越來越複雜,他們接管電子郵件帳戶並在對話執行緒中插入銀行木馬。   惡意軟體是對現有討論的回覆,這是一種強大的社會工程方法,可以保證很高的成功率,因為​​它

如何在執行執行注入bean

轉:https://segmentfault.com/q/1010000007172414?_ea=1264473 如何在多執行緒中注入bean?!​​​​​​​ 問題對人有幫助,內容完整,我也想知道答案0問題沒有實際價值,缺少關鍵內容,沒有改進餘地 前幾天,在sf這裡也提過這個問題,但

謹慎使用多執行的fork

前言 在單核時代,大家所編寫的程式都是單程序/單執行緒程式。隨著計算機硬體技術的發展,進入了多核時代後,為了降低響應時間,重複充分利用多核cpu的資源,使用多程序程式設計的手段逐漸被人們接受和掌握。然而因為建立一個程序代價比較大,多執行緒程式設計的手段也就逐漸被人們認可和喜愛了。 記得在我剛

執行的wait() 與 鎖的關係

我們先看一段程式碼: /** * 計算輸出其他執行緒鎖計算的資料 * */ public class ThreadA { public static void main(String[] args) throws InterruptedException{ Thre

執行的關鍵字volatile的介紹

volatile關鍵字修飾 變數:可以保證變數的可見性和防止程式指令重排序 想要理解volatile為什麼能確保可見性,就要先理解Java中的記憶體模型是什麼樣的。 Java記憶體模型規定了所有的變數都儲存在主記憶體中。每條執行緒中還有自己的工作記憶體,執行緒的工作記

執行同步:基於式同步

    什麼是基於棧式同步?這是一種完全基於非同步環境的執行緒處理之間的同步,可能這讓人有些難以理解,但我們想想一下當你開闢了多條執行緒用於處理某種事物的時候,例如你訪問 Redis 中的 Set 介面,大多數的客戶端都需要阻塞當前執行緒,由另一個執行緒發射訊號通知核心停止阻塞(

[Swift4.2互動教程]八、實用進階-(3)閉包在定時任務、動畫和執行的使用

閉包的使用相當廣泛,它是可以在程式碼中被傳遞和引用的具有獨立功能的模組。雙擊開啟之前建立的空白專案。本文將演示閉包在定時任務、動畫和執行緒中的使用。在左側的專案導航區,開啟檢視控制器的程式碼檔案:ViewController.swift 一、閉包在定時器中的用法 1 import UIKit