您好,登錄后才能下訂單哦!
本篇內容主要講解“通過面試題虛擬機棧的方法技巧”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“通過面試題虛擬機棧的方法技巧”吧!
眾所周知,棧只有進棧和出棧兩種操作,所以它是一種快速有效的分配存儲方式。對于它來說,它不存在垃圾回收問題,但是它的大小是動態的或者固定不變的,因此它會存在棧溢出或者內存溢出問題......
面試官: 打斷一下啊,你剛才說會存在棧溢出和內存溢出問題,那你能分別說一下為什么會出現這種情況嗎?
阿Q: 可以可以,我們知道虛擬機棧由棧幀組成,每一個方法的調用都對應著一個棧幀的入棧。我們可以通過-Xss
參數來設置棧的大小,假設我們設置的虛擬機棧大小很小,當我們調用的方法過多,也就是棧幀過多的話,就會出現StackOverflowError
,即棧溢出問題。
假如我們的棧幀不固定,設置為動態擴展的,那在我們的內存不足時,也就沒有足夠的內存來支持棧的擴展,這個時候就會出現OOM
異常,即內存溢出問題。
面試官: 嗯嗯(點頭狀),示意小伙子思路很清晰呀,那你剛才說到棧幀設置的太小會導致棧幀溢出問題,那我們設置的大點不就可以完全避免棧溢出了嘛。
阿Q: 一聽就是要給我挖坑呀,像我們一般都比較崇尚中庸之道,所以一聽到這種絕對的問題,必須機靈點:不不不,調整棧的大小只可以延緩棧溢出的時間或者說減少棧溢出的風險。
假如一個業務邏輯的方法調用需要5000
次,但是此時拋出了棧溢出的錯誤。我們可以通過設置-Xss
來獲取更大的棧空間,使得調用在7000
次時才會溢出。此時調整棧大小就變得很有意義,因為這樣就會使得業務能正常支持。
那假如是有死遞歸的情況則無論怎么提高棧大小都會溢出,這樣也就沒有任何意義了。
面試官: 好的,那你看一下這個簡單的小程序,你能大體說一下它在內存中的執行過程嗎?
public void test() { byte i = 15; int j = 8; int k = i + j; }
阿Q: 先把該代碼編譯一下,然后查看它的字節碼文件。如上圖中左邊所示,執行過程如下:
首先將要執行的指令地址0
存放到PC
寄存器中,此時,局部變量表和操作數棧的數據為空;
當執行第一條指令bipush
時,將操作數15
放入操作數棧中,然后將PC
寄存器的值置為下一條指令的執行地址,即2
;
當執行指令地址為2
的操作指令時,將操作數棧中的數據取出來,存到局部變量表的1
位置,因為該方法是實例方法,所以0
位置存的是this
的值,PC
寄存器中的值變為3
;
同步驟2和3將8
先放入操作數棧,然后取出來存到局部變量表中,PC
寄存器中的值也由3
->5
->6
;
當執行到地址指令為6
、7
、8
時,將局部變量表中索引位置為1
和2
的數據重新加載到操作數棧中并進行iadd
加操作,將得到的結果值存到操作數棧中,PC
寄存器中的值也由6
->7
->8
->9
;
執行操作指令istore_3
,將操作數棧中的數據取出存到局部變量表中索引為3
的位置,執行return
指令,方法結束。
面試官: 內心OS:這小子貌似還可以呀。說的還不錯,那你能說一下方法中定義的局部變量是否線程安全嗎?
阿Q: 那我再用幾個例子來說一下吧。
public class LocalParaSafeProblem { /** * 線程安全的 * 雖然StringBuilder本身線程不安全, * 但s1 變量只存在于這個棧幀的局部變量表中, * 因為棧幀是每個線程獨立的一份, * 所以這里的s1是線程安全的 */ public static void method01() { // 線程內部創建的,屬于局部變量 StringBuilder s1 = new StringBuilder(); s1.append("a"); s1.append("b"); } /** * 線程不安全 * 因為此時StringBuilder是作為參數傳入, * 外部的其他線程也可以訪問,所以線程不安全 */ public static void method02(StringBuilder stringBuilder) { stringBuilder.append("a"); stringBuilder.append("b"); } /** * 線程不安全 * 此時StringBuilder被多個線程同時操作 */ public static void method03() { StringBuilder stringBuilder = new StringBuilder(); new Thread(() -> { stringBuilder.append("a"); stringBuilder.append("b"); }, "t1").start(); method02(stringBuilder); } /** * 線程不安全 * 因為此時方法將StringBuilder返回出去了 * 外面的其他線程可以直接修改StringBuilder這個引用了所以不安全 */ public static StringBuilder method04() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("a"); stringBuilder.append("b"); return stringBuilder; } /** * StringBuilder是線程安全的 * 此時stringBuilder值在當前棧幀的局部變量表中存在, * 其他線程無法訪問到該引用, * 方法執行完成之后此時局部變量表中的stringBuilder的就銷毀了 * 返回的stringBuilder.toString()線程不安全 * 最后的返回值將toString返回之后,其他線程可以操作而String本身是線程不安全的。 */ public static String method05() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("a"); stringBuilder.append("b"); return stringBuilder.toString(); } }
到此,相信大家對“通過面試題虛擬機棧的方法技巧”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。