Android面試集錦系列(3)——實戰美團--Java記憶體模型
面試題:說說Java的記憶體模型
說實話,把我問的有點“蒙”,確實知道一二,但在工作中很少總結這個方面,以前也專門看過,但那又是太遙遠的事情了。硬著頭皮把一些想法和記憶說了出來。
有讀者會納悶了,這樣的題都能“嚇蒙”你?
面試官不一定是最好的面試者,就像教練不一定非要是世界冠軍。
面試官的套路和我預想的不一樣,沒有關注專案經驗、管理和架構設計,上來就Java基礎到Androd基礎,而且極其細緻。
Java的記憶體模型
Java開發人員並不需要像C/C++開發人員,需要時刻注意記憶體的分配和釋放,而是全權交給虛擬機器(JVM)去管理,自然關於記憶體管理或是記憶體的模型、結構對Java開發來說就是一個“黑箱”。
兩眼一抹黑似乎也不影響寫Java的程式碼。但我也說過,瞭解一些內部的機制或者是自己認為不重要的東西,也許會很有幫助。
最簡單的,我們也應該瞭解Java的堆和棧。而我們所謂的記憶體管理,基本上指對堆記憶體的管理,那堆記憶體在JVM的記憶體結構中的那個位置呢?
什麼是JVM記憶體
Java原始碼檔案(.java)會被Java編譯器編譯為位元組碼檔案(.class),然後由JVM中的類載入器載入各個類的位元組碼檔案,載入完畢之後,交由JVM執行引擎執行。
JVM在執行Java程式的過程中會把它所管理的記憶體劃分為若干個不同的資料區域。
JVM會用一段空間來儲存程式執行期間需要用到的資料和相關資訊,這段空間一般被稱作為Runtime Data Area(執行時資料區),也就是我們常說的JVM記憶體。

瞭解清楚JVM的記憶體結構會更有助於我們理解Java的記憶體模型。
我們可以把上圖的“執行時資料區”分為執行緒私有和共享資料區兩大類。其中執行緒私有的資料區包含程式計數器、虛擬機器棧、本地方法區,所有執行緒共享的資料區包含Java堆、方法區,在方法區內有一個常量池。

-
程式計數器(PC Register)
記錄正在執行的虛擬機器位元組碼的地址。和計算機組成原理中提到的程式計數器PC概念類似,是執行緒私有的,用來記錄當前執行的位元組碼位置。
-
虛擬機器棧(JVM Stack)
也就是我們常常所說的棧。
方法執行的記憶體區,每個方法執行時會在虛擬機器棧中建立棧幀。虛擬機器棧的生命週期與執行緒相同,每個方法(不包含native方法)執行的同時都會建立一個棧幀結構,方法執行過程,對應著虛擬機器棧的入棧到出棧的過程。

-
本地方法棧(Native Method Stack)
本地方法棧則為虛擬機器使用到的Native方法提供記憶體空間。
-
Java堆(Heap)
Java堆一般是JVM管理的記憶體中最大的一塊,堆在主記憶體中,是被所有執行緒共享的一塊記憶體區域,其隨著JVM的建立而建立,是用來儲存物件本身的以及陣列,同時JAVA堆也是GC管理的主要區域。
-
方法區(Method Area)
主要存放的是已被虛擬機器載入的類資訊、常量、靜態變數、編譯器編譯後的程式碼等資料。
-
常量池(Runtime Constant Pool)
存放編譯器生成的各種字面量和符號引用,是方法區的一部分。
記憶體模型
Java記憶體模型即Java Memory Model,簡稱JMM。JMM定義了Java 虛擬機器(JVM)在計算機記憶體(RAM)中的工作方式。Java執行緒之間的通訊由JMM控制,JMM決定一個執行緒對共享變數的寫入何時對另一個執行緒可見。
從抽象的角度來看,JMM定義了執行緒和主記憶體之間的抽象關係:執行緒之間的共享變數儲存在主記憶體(上面提到的Java堆記憶體)中,每個執行緒都有一個私有的本地記憶體,本地記憶體中儲存了該執行緒以讀/寫共享變數的副本。
在指令式程式設計中,執行緒之間的通訊機制有兩種:共享記憶體和訊息傳遞。
Java記憶體模型與上面提到的JVM執行時資料區(JVM Runtime Data Areas)兩個概念容易混淆。JVM 執行時資料區定義了JVM執行期記憶體的管理劃分,而Java記憶體模型定義了程式中各個共享變數的訪問規則。
自己的面試總結
關於Java的記憶體模型,我覺得對於Android應用開發比較有益的就是:更容易理解執行緒安全和併發程式設計的問題。而後面面試官確實也問到了執行緒安全,可能這也是一個組合套路吧。
面試完後,雖然有很多題答得都不是很理想,不過對於我這樣的“過來人”來說,很清楚面試時你回答的內容並不是最重要的(大多數時候)。重要的是什麼?看完這個系列的讀者應該心裡有數。
附上自己的面試總結:
-
Java部分準備不充分。
在面試前我對這個職位的資訊收集並不充分,我的側重點在Android的專案框架和技術管理上。但美團一面的面試官視乎是比較重基礎知識,而且每個點都問得比較仔細。
-
沒有問面試官的姓名。
下來都不好和麵試官做朋友,不是嗎?萬一以後是同事,還不知道對方是誰也有點尷尬。以前有過,和一個同事處了一段時間了,他才告訴我之前是他面的我。
-
表達了一些負面資訊。
解釋了一些不足的地方,個人一直不喜歡“強調”負面資訊,在我的一些表達中,還是不自覺的先抑後揚了,不過好在面試官視乎不太在意。
“標準答案”
標準答案為何打引號,請關注 Android面試集錦系列(2)——設計模式 的說明。
面試題:Java的記憶體模型
標準答案:Java記憶體模型即Java Memory Model,簡稱JMM。JMM定義了Java 虛擬機器(JVM)在計算機記憶體(RAM)中的工作方式。程式中的變數儲存在主記憶體中,每個執行緒擁有自己的工作記憶體並存放變數的拷貝,執行緒讀寫自己的工作記憶體,通過主記憶體進行變數的互動。JMM就是規定了工作記憶體和主記憶體之間變數訪問的細節,通過保障原子性、有序性、可見性來實現執行緒的有效協同和資料的安全。
面試題:JVM如何判斷一個物件例項是否應該被回收?
標準答案:垃圾回收器會建立有向圖的方式進行記憶體管理,通過GC Roots來往下遍歷,當發現有物件處於不可達狀態的時候,就會對其標記為不可達,以便於後續的GC回收。
面試題:說說JVM的垃圾回收策略。
標準答案:JVM採用分代垃圾回收。在JVM的記憶體空間中把堆空間分為年老代和年輕代。將大量建立了沒多久就會消亡的物件儲存在年輕代,而年老代中存放生命週期長久的例項物件。
最後
針對於上面的面試題我總結出了網際網路公司Android程式設計師面試涉及到的絕大部分面試題及答案做成了文件和架構視訊資料免費分享給大家【 包括高階UI、效能優化、架構師課程、NDK、Kotlin、混合式開發(ReactNative+Weex)、Flutter等架構技術資料 】,希望能幫助到您面試前的複習且找到一個好的工作,也節省大家在網上搜索資料的時間來學習。
資料獲取方式:加入Android架構交流QQ群聊:513088520 ,進群即領取資料!!!
點選連結加入群聊【Android移動架構總群】: 加入群聊

資料大全