Java 面試- JVM 的Stack 和Heap - Laugh Now

文章推薦指數: 80 %
投票人數:10人

Heap 是Class Type 創建實例時存放資料的地方,在Heap 創建完成後會回傳所在的記憶體位址。

變數可能是Primitive Type 或Class / Reference Type 。

若是 ... HomeArchivesCategoriesTagsAbout2016-09-14發表2021-03-07更新Technique / Java12分鐘讀完(大約1852個字)Java面試-JVM的Stack和Heap請比較JVM記憶體的Stack和Heap這題非常容易考到,而且翻譯十分混亂,盡量用原文去表達比較好,Stack繁中為堆疊、簡中為棧,Heap繁中為堆積、簡中為堆。

要特別注意的是,這邊的Stack和Heap並不是在指資料結構,而是指JVM記憶體管理的部分。

聲明:這些內容比較簡略、粗糙,忽略了很多細節,只揀選能回答到問題的部份去解說,並不是百分之百準確,除非每一題都有兩個小時以上的回答時間,否則這些內容應該足夠回答到面試官想聽的點。

如果你真的很在乎每一個部份的細節內容,你不該讀我的筆記,而是去讀文件,自己寫自己的筆記。

當然,我會隨著越講越深入而帶入更多細節的部份,但是我也需要考量文章篇幅以及流暢度。

若有任何錯誤或遺漏之處,請在底下用力鞭我,不用客氣,隱瞞缺失比直指痛處更讓人害怕。

首先,Java檔經過編譯後所產生的Class檔(bytecode),只能運行在JVM上,而JVM在運算時,如同一般電腦一樣,需要記憶體儲存運算所需的資料及指令,而JVM記憶體中的Stack和Heap最常被拿來做比較(記憶體中當然還有其他部份,包括MethodArea、PCRegister、NativeMethodStack,但不在本篇討論範圍)。

JVM記憶體的Stack和Heap絕對不要和其他同名的東西搞混,在這裡是做為JVM儲存資料或指令的區域,和其他同名的東西無關,請把它當作平行宇宙看待。

Java中的資料型態分為兩種:PrimitiveType基本型態共有8種:int、short、long、byte、float、double、boolean、char。

這種類型是通過如inta=3;longb=123L;的方式宣告。

長度及生命週期都為可知(程式碼區塊執行完就扔掉)。

運算速度快,但長度與內容受限。

ClassType/ReferenceType類別型態/參考型態其他大都屬於此類別,如Integer、String、Long以及自行定義的類別(ex.User)等。

這種類型通常都需要用new去創建,如Useruser=newUser("Mark");。

因為是在執行時才動態創建,所以長度及生命週期都不可預知。

靈活但運算較耗時。

Stack堆疊、棧複習一下前一章所提到的:每一個Thread擁有自己的Stack,Stack是用來儲存函數路徑及區域變數,Thread之間的Stack互相獨立。

Stack是一種後進先出(FILO)的容器,具有存取速度快和管理簡單的特點。

由於Java中變數跟函式的生命週期都為後進先出,也就是越晚產生的會越先被回收或銷毀,所以Stack非常適合做為這種可預測性的資料,如區域變數、函式參數與函式返回位址等等,的儲存容器。

因為Stack中的資料生命週期都是規律的,所以由系統自行去產生和回收空間即可,程式設計師不需要介入。

Heap堆積、堆還記得前一章提到Process的MemorySpace是專門儲存共享資料/資源的嗎?Heap就屬於這種共享資料。

ClassType在創建實例(Instance)時(ex.newUser("Mark");),就是把資料放置於Heap中,系統會在Heap內找一塊區域放置此User實例的屬性資料,也因為Heap存放的是共享資料,所以不論該實例是由哪一個Thread所創建的,同Process底下的其他Thread也可以進行存取。

因為實例的生命週期是不可預知的,系統較難以自行去回收空間,所幸,Java的特色之一就是GarbageCollection機制(簡稱GC)**,會自動去清理Heap內已經沒有被參考(Reference)**的資料,當然,程式設計師可以撰寫程式去控制GC的行動,不過大多數情況下都不建議如此,過多的介入反而可能造成資源的浪費,未來可能會再寫一篇簡述GC是如何判斷哪些資料應該被清理。

範例可能有人看到這邊仍是霧煞煞,以下我用簡單的程式來講解資料儲存實際上是如何運作。

123inta=123;longb=456L;Userc=newUser("Mark",Gender.MALE);以上程式碼的資料儲存順序大致上可以視為以下流程圖*(在此先不考慮ConstantPool)*。

前兩行指令都是PrimitiveType,會在Stack內建立變數a和b,並將實際值123和456L存放於變數內。

第三行指令要切分成兩個部份,等號右邊及左邊,首先是右邊的部份,先以name和gender參數創建一個User實例,此時會在Heap中的一個位址(ex.0x1234)存放實例的屬性資料(ex.name、gender、address…),並將實例所在的記憶體位址(0x1234)指定給變數c參考。

這篇是以變數為例子去比較兩者儲存方式的不同,至於「Stack如何儲存函式」、「常數池(ConstantPool)是什麼」、「實例的method存放在哪」等等問題,留待後面文章再做解答。

從以上的例子可以發現,Stack內的變數值分為兩種類型,一種為ValueType實質類別,儲存的是實際的值(ex.123、456L);另一種為ReferenceType參考類別,儲存的是資料在Heap中的記憶體位址(ex.0x1234)。

總結Stack和Heap是JVM記憶體儲存資料或指令的區域。

Java的資料類型分為兩種:PrimitiveType和ClassType。

Stack存取速度快,但資料長度及生命週期必須是預知的,用來儲存區域變數、函式參數與函式返回位址等資料。

Heap是ClassType創建實例時存放資料的地方,在Heap創建完成後會回傳所在的記憶體位址。

變數可能是PrimitiveType或Class/ReferenceType。

若是PrimitiveType,則在Stack內的變數值為實際值;若是Class/ReferenceType,實例資料會儲存在Heap中,Stack內的變數值為實例在Heap中的記憶體位址。

Useruser=newUser("Mark");的行為簡單來說是:i.創建並儲存User實例(name=Mark)於Heap中。

ii.儲存完成後,回傳資料所在的記憶體位址。

iii.在Stack中新增變量user。

iv.將ii.所傳回的記憶體位址指定給user參考。

#interviewjvmstackheapStructuresandArchitecturesforOptimizingDatabase(EN)Java面試-Program、Process和Thread評論markleetwProductManager/EngineerTaipei,Taiwan文章22分類11標籤40追蹤最新文章2021-02-18透過Gmail收發個人網域的電子郵件Technique/Misc2020-05-31《生時間》讀書心得筆記Reading2017-12-09製作一支應聲蟲LineBotTechnique/Python2017-10-13Shebang:*nix的使用預設程式執行Technique/Linux2017-01-28StructuresandArchitecturesforOptimizingDatabase(EN)Technique/Database×



請為這篇文章評分?