国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - 編程技術 - 面試官太難伺候?一個try-catch問出這么多花樣

面試官太難伺候?一個try-catch問出這么多花樣

2022-01-25 22:34Hollis 編程技術

今天趁著B哥也在,我們就來好好總結一下TCF相關的知識點,期待下次與面試官對線五五開!

面試官太難伺候?一個try-catch問出這么多花樣

剛剛面試回來的B哥又在吐槽了:現在的面試官太難伺候了,放著好好的堆、棧、方法區不問,上來就讓我從字節碼角度給他分析一下try-catch-finally(以下簡稱TCF)的執行效率......

我覺得應該是面試官在面試的過程中看大家背的八股文都如出一轍,覺得沒有問的必要,便拐著彎的考大家的理解。今天趁著B哥也在,我們就來好好總結一下TCF相關的知識點,期待下次與面試官對線五五開!

環境準備:IntelliJ IDEA 2020.2.3、JDK 1.8.0_181

執行順序

我們先來寫一段簡單的代碼:

public static int test1() {
    int x = 1;
    try {
        return x;
    } finally {
        x = 2;
    }
}

答案是1不是2,你答對了嗎?

大家都知道在TCF中,執行到return的時候會先去執行finally中的操作,然后才會返回來執行return,那這里為啥會是1呢?我們來反編譯一下字節碼文件。

命令:javap -v xxx.class

面試官太難伺候?一個try-catch問出這么多花樣

字節碼指令晦澀難懂,那我們就用圖解的方式來解釋一下(我們先只看前7行指令):首先執行 int x = 1;

面試官太難伺候?一個try-catch問出這么多花樣

然后我們需要執行try中的return x;

面試官太難伺候?一個try-catch問出這么多花樣

此時并不是真正的返回x的值,而是將x的值存到局部變量表中作為臨時存儲變量進行存儲,也就是對該值進行保護操作。

最后進入finally中執行x=2;

面試官太難伺候?一個try-catch問出這么多花樣

此時雖然x已經被賦值為2了,但是由于剛才的保護操作,在執行真正的return操作時,會將被保護的臨時存儲變量入棧返回。

為了更好的理解上述操作,我們再來寫一段簡單代碼:

public static int test2() {
    int x = 1;
    try {
        return x;
    } finally {
        x = 2;
        return x;
    }
}

大家思考一下執行結果是幾?答案是2不是1。

我們再來看下該程序的字節碼指令

面試官太難伺候?一個try-catch問出這么多花樣

通過對比發現,第6行一個是iload_1,一個是iload_0,這是由什么決定的呢?原因就是我們上邊提到的保護機制,當在finally中存在return語句時,保護機制便會失效,轉而將變量的值入棧并返回。

小結

  • return的執行優先級高于finally的執行優先級,但是return語句執行完畢之后并不會馬上結束函數,而是將結果保存到棧幀中的局部變量表中,然后繼續執行finally塊中的語句;
  • 如果finally塊中包含return語句,則不會對try塊中要返回的值進行保護,而是直接跳到finally語句中執行,并最后在finally語句中返回,返回值是在finally塊中改變之后的值;

finally 為什么一定會執行

細心地小伙伴應該能發現,上邊的字節碼指令圖中第4-7行和第9-12行的字節碼指令是完全一致的,那么為什么會出現重復的指令呢?

首先我們來分析一下這些重復的指令都做了些什么操作,經過分析發現它們就是x = 2;return x;的字節碼指令,也就是finally代碼塊中的代碼。由此我們有理由懷疑如果上述代碼中加入catch代碼塊,finally代碼塊對應的字節碼指令也會再次出現。

public static int test2() {
    int x = 1;
    try {
        return x;
    } catch(Exception e) {
        x = 3;
    } finally {
        x = 2;
        return x;
    }
}

反編譯之后

面試官太難伺候?一個try-catch問出這么多花樣

果然如我們所料,重復的字節碼指令出現了三次。讓我們回歸到最初的問題上,為什么finally代碼的字節碼指令會重復出現三次呢?

原來是JVM為了保證所有異常路徑和正常路徑的執行流程都要執行finally中的代碼,所以在try和catch后追加上了finally中的字節碼指令,再加上它自己本身的指令,正好三次。這也就是為什么finally 一定會執行的原因。

finally一定會執行嗎?

為什么上邊已經說了finally中的代碼一定會執行,現在還要再多此一舉呢?請看

在正常情況下,它是一定會被執行的,但是至少存在以下三種情況,是一定不執行的:

  • try語句沒有被執行到就返回了,這樣finally語句就不會執行,這也說明了finally語句被執行的必要而非充分條件是:相應的try語句一定被執行到;
  • try代碼塊中有System.exit(0);這樣的語句,因為System.exit(0);是終止JVM的,連JVM都停止了,finally肯定不會被執行了;
  • 守護線程會隨著所有非守護線程的退出而退出,當守護線程內部的finally的代碼還未被執行到,非守護線程終結或退出時,finally 肯定不會被執行;

TCF 的效率問題

說起TCF的效率問題,我們不得不介紹一下異常表,拿上邊的程序來說,反編譯class文件后的異常表信息如下:

面試官太難伺候?一個try-catch問出這么多花樣

  • from:代表異常處理器所監控范圍的起始位置;
  • to:代表異常處理器所監控范圍的結束位置(該行不被包括在監控范圍內,是前閉后開區間);
  • target:指向異常處理器的起始位置;
  • type:代表異常處理器所捕獲的異常類型;

圖中每一行代表一個異常處理器

工作流程:

  1. 觸發異常時,JVM會從上到下遍歷異常表中所有的條目;
  2. 比較觸發異常的行數是否在from-to范圍內;
  3. 范圍匹配之后,會繼續比較拋出的異常類型和異常處理器所捕獲的異常類型type是否相同;
  4. 如果類型相同,會跳轉到target所指向的行數開始執行;
  5. 如果類型不同,會彈出當前方法對應的java棧幀,并對調用者重復操作;
  6. 最壞的情況下JVM需要遍歷該線程 Java 棧上所有方法的異常表;

拿第一行為例:如果位于2-4行之間的命令(即try塊中的代碼)拋出了Class java/lang/Exception類型的異常,則跳轉到第8行開始執行。

8: astore_1是指將拋出的異常對象保存到局部變量表中的1位置處

從字節碼指令的角度來講,如果代碼中沒有異常拋出,TCF的執行時間可以忽略不計;如果代碼執行過程中出現了上文中的第6條,那么隨著異常表的遍歷,更多的異常實例被構建出來,異常所需要的棧軌跡也在生成。該操作會逐一訪問當前線程的棧幀,記錄各種調試信息,包括類名、方法名、觸發異常的代碼行數等等。所以執行效率會大大降低。

原文地址:https://mp.weixin.qq.com/s/qYvMpbOXcJ77XQbK_MC8MA

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 91亚洲精品乱码久久久久久蜜桃 | 国产在线二区 | 色www精品视频在线观看 | 欧美激情一区二区 | 欧美综合区 | 婷婷激情久久 | 亚洲欧美在线视频 | 一区不卡| 日韩免费视频 | 国产精品久久久久久吹潮 | 日韩有码在线观看 | 欧美精三区欧美精三区 | 日韩欧美在线不卡 | 最近日本韩国高清免费观看 | 国产香蕉视频在线播放 | av网站观看 | 国产精品毛片无码 | 91亚洲国产 | a黄视频 | 欧美成人a | 天天色天天射天天操 | 久久久91精品国产一区二区三区 | 午夜在线视频 | 国产一区二区久久久 | 中文字幕成人在线 | av资源中文在线 | 日韩在线观看一区 | 欧美在线视频网站 | 亚洲成av人片在线观看 | 亚洲一区欧美一区 | 亚洲激情在线 | 在线99 | 国产欧美成人 | 婷婷丁香综合 | 精品久久久网站 | 午夜精品久久久久久 | 亚洲精品乱码久久久久久金桔影视 | 亚洲二区在线 | 午夜成人免费视频 | 一区二区三区高清 | 国产日韩欧美 |