<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      安卓筆記俠

      專注安卓開發(fā)

      導(dǎo)航

      深入理解Java虛擬機06--虛擬機字節(jié)碼執(zhí)行引擎

      一.前言

      物理機的執(zhí)行引擎是直接在物理硬件如CPU、操作系統(tǒng)、指令集上運行的,但是對于虛擬機來講,他的執(zhí)行引擎由自己實現(xiàn)。 執(zhí)行引擎有統(tǒng)一的外觀(Java虛擬機規(guī)范),不同類型的虛擬機都遵循了這一規(guī)范,輸入字節(jié)碼文件,解析字節(jié)碼處理,然后輸出結(jié)果。

      二.運行時棧幀結(jié)構(gòu)

      1、棧幀概念
      棧幀(Stack Frame)用于支持方法調(diào)用和執(zhí)行的數(shù)據(jù)結(jié)構(gòu),包含了局部變量表、操作數(shù)棧、動態(tài)連接和方法返回地址。

      • 局部變量表大小(max_locals),棧幀深度在編譯時已經(jīng)確定,并寫入到了Code屬性中;
      • 執(zhí)行引擎運行的所有字節(jié)碼指令都只針對當(dāng)前棧進(jìn)行操作;

      2、局部變量表
      局部變量表存儲了方法參數(shù)以及方法內(nèi)定義的局部變量。

      • Slot(變量槽):局部變量表容量最小單位,可以存放32位以內(nèi)的數(shù)據(jù)類型;
      • refrence:
        • 直接或者間接找到到該對象在“堆內(nèi)存”中數(shù)據(jù)存放的起始地址索引;
        • 直接或者間接找到對象所屬數(shù)據(jù)類型在方法區(qū)中存儲的類型信息;
      • 局部變量表建立在線程的堆棧上,所以操作兩個連續(xù)的slot是否為原子操作,都不會引起數(shù)據(jù)安全問題,但是如果是64位的話,不允許任何方式單獨訪問其中的一個;
      • this:實例方法(非static)默認(rèn)第一個(第0位索引)slot為當(dāng)前對象自己的引用;
      • slot重用:
        • 當(dāng)前字節(jié)碼的pc計數(shù)器超出某個變量的作用域,那這個變量的slot可以交給別的變量使用;
        • 影響到正常的Java垃圾回收機制;
      • 賦null:因為上述slot重用的原因,當(dāng)方法域內(nèi)前面有局部變量定義了大內(nèi)存實際不再使用的變量,緊接著后面的代碼又是一個耗時的操作,這個時候及時賦null就顯得有大的意義。因為一旦觸發(fā)后,這部分的slot就可以被重用了。看起來就像是方法區(qū)內(nèi)部進(jìn)行“類gc"操作一樣。但是,并不是任何時候都要進(jìn)行賦null.以恰當(dāng)?shù)淖兞孔饔糜騺砜刂谱兞炕厥諘r間才是最優(yōu)雅的方式,并且賦null值操作在經(jīng)過JIT編譯優(yōu)化后會被消除掉,這樣的話實際是沒有任何意義的。
      • 初始值:和類變量不同,局部變量系統(tǒng)不會自動賦初始值,所以沒有賦值是無法使用的,編譯都無法通過。即使通過,字節(jié)碼校驗階段也會檢查出來而導(dǎo)致類加載失??;

      3、操作數(shù)棧(Operand Stack)

      • 操作棧,后入先出;
      • 最大深度:Code屬性表中的max_stacks;
      • 32位數(shù)據(jù)類型所占棧容量為1,64位所占容量為2;
      • 棧元素的數(shù)據(jù)類型必須和棧指令保持一致
      • 兩個棧幀之間可以存在一部分的重疊,共享數(shù)據(jù),這樣在方法調(diào)用的時候避免的額外的參數(shù)復(fù)制。
      • Java虛擬機的解釋執(zhí)行引擎也是:基于棧的執(zhí)行引擎;

      4、動態(tài)連接(Dynamic Linking)
      字節(jié)碼中的方法的調(diào)用都是通過常量池中指定方法的符號作為參數(shù)

      • 靜態(tài)解析:這種符號有的是類加載階段或者首次使用初始化的時候轉(zhuǎn)化為直接的引用
      • 動態(tài)連接:另外一部分是在運行時轉(zhuǎn)化為直接引用

      5、方法返回地址

      • 退出:
        • 正常退出:遇到返回的字節(jié)碼指令;
        • 異常退出:本方法異常表中沒有匹配的異常;
      • 退出后,恢復(fù)上層方法的局部變量表和操作棧,有返回值就把返回值壓入上層調(diào)用者的棧中;

       

      三.方法調(diào)用

      定義:確定被調(diào)用方法的版本
      1、解析

      • 編譯器可知,運行期不可變。這類方法的調(diào)用成為解析,在類加載階段進(jìn)行解析。
      • 靜態(tài)方法、私有方法、實例構(gòu)造器方法、父類方法,符合上述條件。特點是:
        • 只能被invokestatic和invokespecial指令調(diào)用
        • 不可繼承或者重寫,編譯時已經(jīng)確定了一個版本。
        • 在類加載時會把符合引用解析為該方法的直接引用。
        • 非虛方法(注意final也是非虛方法,其他的都是虛方法)

      2、靜態(tài)分派

      • 概念:根據(jù)靜態(tài)類型來定位方法的執(zhí)行版本
      • 典型代表:方法的重載(方法名相同,參數(shù)類型不同)
      • 發(fā)生時間:編譯階段

      3、動態(tài)分派

      • 概念:調(diào)用invokevirtual時,把常量池中的類方法符號解析到了不同的直接引用上。
      • 典型代表:重寫,多態(tài)的重要體現(xiàn)
      • 過程:
        • 執(zhí)行invokevitual指令
        • 在虛方法表(類加載階段,類變量初始化結(jié)束后會初始化虛方法表)中查找方法,沒有向上的父類進(jìn)行查找
      • 方法宗量:方法的接收者與方法參數(shù)的總稱
      • 單分派和多分派:
        • 只有一個宗量作為方法的選擇依據(jù),稱為單分派。多個,則稱為多分派。
        • 當(dāng)前的Java是靜態(tài)多分派、動態(tài)單分派的語言;

      四.動態(tài)語言支持

      • 特點:變量無類型,變量的值才有類型

      • invoke包:Java實現(xiàn)動態(tài)語言新增的包

      五.指令集

      • 基于棧的指令集
        • 過程:入棧、計算、出棧
        • 優(yōu)點:
          • 可移植性,不依賴于硬件
          • 代碼緊湊
        • 缺點:
          • 速度較慢
          • 產(chǎn)生相當(dāng)多的指令數(shù)量
          • 頻繁內(nèi)存訪問
      • 基于寄存器的指令集
        • 代表:x86

       

      六.方法內(nèi)聯(lián)

      • 方法內(nèi)聯(lián)的方式是通過吧“目標(biāo)方法”的代碼復(fù)制到發(fā)起調(diào)用的方法內(nèi),避免真實的方法調(diào)用。
      • 內(nèi)聯(lián)消除了方法調(diào)用的成本,還為其他優(yōu)化手段建立良好的基礎(chǔ)。
      • 編譯器在進(jìn)行內(nèi)聯(lián)時,如果是非虛方法,那么直接內(nèi)聯(lián)。如果遇到虛方法,則會查詢當(dāng)前程序下是否有多個目標(biāo)版本可供選擇,如果查詢結(jié)果只有一個版本,那么也可以內(nèi)聯(lián),不過這種內(nèi)聯(lián)屬于激進(jìn)優(yōu)化,需要預(yù)留一個逃生門(Guard條件不成立時的Slow Path),稱為守護(hù)內(nèi)聯(lián)。
      • 如果程序的后續(xù)執(zhí)行過程中,虛擬機一直沒有加載到會令這個方法的接受者的繼承關(guān)系發(fā)現(xiàn)變化的類,那么內(nèi)聯(lián)優(yōu)化的代碼可以一直使用。否則需要拋棄掉已經(jīng)編譯的代碼,退回到解釋狀態(tài)執(zhí)行,或者重新進(jìn)行編譯

      七.逃逸分析

      逃逸分析的基本行為就是分析對象動態(tài)作用域:當(dāng)一個對象在方法里面被定義后,它可能被外部方法所引用,這種行為被稱為方法逃逸。被外部線程訪問到,被稱為線程逃逸。
      如果對象不會逃逸到方法或線程外,可以做什么優(yōu)化?

      • 棧上分配:一般對象都是分配在Java堆中的,對于各個線程都是共享和可見的,只要持有這個對象的引用,就可以訪問堆中存儲的對象數(shù)據(jù)。但是垃圾回收和整理都會耗時,如果一個對象不會逃逸出方法,可以讓這個對象在棧上分配內(nèi)存,對象所占用的內(nèi)存空間就可以隨著棧幀出棧而銷毀。如果能使用棧上分配,那大量的對象會隨著方法的結(jié)束而自動銷毀,垃圾回收的壓力會小很多。
      • 同步消除:線程同步本身就是很耗時的過程。如果逃逸分析能確定一個變量不會逃逸出線程,那這個變量的讀寫肯定就不會有競爭,同步措施就可以消除掉。
      • 標(biāo)量替換:不創(chuàng)建這個對象,直接創(chuàng)建它的若干個被這個方法使用到的成員變量來替換。

      八.小結(jié)

        在前面我們已經(jīng)了解到棧幀、方法區(qū)的內(nèi)存時線程私有的,本篇更加詳細(xì)的講了方法是怎么找到并執(zhí)行的。Java虛擬機規(guī)范:輸入字節(jié)碼,解析字節(jié)碼處理,輸出結(jié)果。首先,棧幀包含了局部變量表、操作數(shù)棧、動態(tài)連接、方法返回地址。字節(jié)碼中的方法都是通過常量池中的符號作為參數(shù)指定的,有些編譯解析確定,有些運行行時轉(zhuǎn)化為直接引用。首先記住,JVM是基于棧的執(zhí)行引擎。棧有著先入后出的特點,執(zhí)行引擎的指令也僅執(zhí)行當(dāng)前棧。而局部變量表存儲了方法內(nèi)需要的變量信息,是以Slot 為單位進(jìn)行存儲,超出操作域后,原本占用的內(nèi)存區(qū)域可以被其他的局部變量使用,類似“回收”。然后,記住Java是靜態(tài)多分派,動態(tài)單分派的語言。靜態(tài)分派,如方法的重載。通過方法的參數(shù)不同就可以確定要調(diào)用哪個方法,這個再編譯階段就定好。動態(tài)分派,如方法的重寫。執(zhí)行方法時,有一個虛方法表。這這個表里搜索,自己有就執(zhí)行自己的,沒有向上找父類的。這個是Java實現(xiàn)多態(tài)的重要原理。Java也有支持動態(tài)語言的invoke包,平時用的較少。

      posted on 2018-08-06 13:37  安卓筆記俠  閱讀(463)  評論(0)    收藏  舉報

      主站蜘蛛池模板: 久久88香港三级台湾三级播放| 九九热在线免费播放视频| 泾阳县| 亚洲欧洲色图片网站| 久久一卡二卡三卡四卡| 国产一区二区丰满熟女人妻 | 亚洲永久一区二区三区在线| 久久久久综合一本久道| 综合久久av一区二区三区| 亚洲欧美激情在线一区| 丁香婷婷综合激情五月色| 乱色精品无码一区二区国产盗 | 国产精品国三级国产av| 国产一区二区三区导航| 日韩欧美不卡一卡二卡3卡四卡2021免费| 亚洲欧美另类激情综合区蜜芽 | 东京热人妻丝袜无码AV一二三区观 | 亚洲乱码中文字幕小综合| 精品亚洲女同一区二区| 亚洲另类激情专区小说图片| 免费无码国模国产在线观看| 亚洲成在人线AV品善网好看| 熟妇人妻无码中文字幕老熟妇 | 在线综合亚洲欧洲综合网站| 日韩高清不卡一区二区三区| 自拍日韩亚洲一区在线| 国内少妇人妻偷人精品| 日韩欧国产美一区二区在线| 四虎影院176| 成人永久性免费在线视频| 国产一区日韩二区三区| 国产精品久久久久久爽爽爽| 蜜臀av日韩精品一区二区| 真实国产老熟女无套中出| 91福利一区福利二区| 精品日韩亚洲av无码| 亚洲精品天堂在线观看| 亚洲国产午夜精品理论片| 国产91成人亚洲综合在线| 午夜精品一区二区三区免费视频 | 亚洲日韩久热中文字幕|