Java JVM與內(nèi)存分配-Android面試準備2019-2-3

Java程序運行機制與JVM

Java編寫的程序需要經(jīng)過編譯盖彭,但編譯不會生成特定平臺的機器碼枫振,而是生成一種與平臺無關(guān)只面向JVM的字節(jié)碼(即.class文件)柑营。這種字節(jié)碼必須使用Java解釋器來解釋執(zhí)行氨淌,Java里負責解釋執(zhí)行字節(jié)碼文件就是JVM泊愧。JVM是可運行Java字節(jié)碼文件的虛擬計算機。

JVM =?類加載器 +?執(zhí)行引擎 +?運行時數(shù)據(jù)區(qū)域盛正。

類加載器將Class文件加載到JVM中的運行時數(shù)據(jù)區(qū)域删咱,執(zhí)行引擎負責執(zhí)行字節(jié)碼文件。

Java內(nèi)存分配的粗糙分法

Java把內(nèi)存劃分成兩種:棧內(nèi)存與堆內(nèi)存豪筝√底蹋基本類型變量和對象的引用變量都是在函數(shù)的棧內(nèi)存中分配,而堆內(nèi)存用來存放由new創(chuàng)建的對象和數(shù)組壤蚜。在堆中產(chǎn)生了一個數(shù)組或?qū)ο笾蠹垂眩梢栽跅V卸x一個特殊的變量,讓棧中的這個變量的取值等于數(shù)組或?qū)ο笤诙褍?nèi)存中的首地址袜刷,棧中的這個變量就成了數(shù)組或?qū)ο蟮囊米兞看细弧R米兞吭诔绦蜻\行到其作用域之外后被釋放(其實就類似于局部變量的釋放)。數(shù)組和對象在沒有引用變量指向它的時候變?yōu)槔罚陔S后的一個不確定的時間被垃圾回收器收走墩蔓。

Java內(nèi)存分配的準確分法

Java虛擬機所管理的內(nèi)存包括以下幾個運行時數(shù)據(jù)區(qū)域。

Java虛擬機運行時數(shù)據(jù)區(qū)

程序計數(shù)器

程序計數(shù)器(線程私有)是一塊較小的內(nèi)存空間萧豆,它可以看作是當前線程所執(zhí)行的字節(jié)碼的行號指示器奸披。由于Java虛擬機的多線程是通過線程輪流切換并分配處理器執(zhí)行時間的方式來實現(xiàn)的,因此為了線程切換后能恢復(fù)到正確的執(zhí)行位置涮雷,每條線程都需要有個獨立的程序計數(shù)器阵面。

虛擬機棧

Java虛擬機棧(線程私有)的生命周期與線程相同。虛擬機棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個方法在執(zhí)行的同時都會創(chuàng)建一個棧幀用于存儲局部變量表、操作數(shù)棧样刷、動態(tài)鏈接仑扑、方法出口等信息。每一個方法從調(diào)用直至執(zhí)行完成的過程置鼻,就對應(yīng)著一個棧幀在虛擬機棧中入棧到出棧的過程镇饮。

經(jīng)常有人把Java內(nèi)存區(qū)分為堆內(nèi)存和棧內(nèi)存,這種分法比較粗糙箕母。其中所指的"棧"就是現(xiàn)在講的虛擬機棧储藐,或者說是虛擬機棧中局部變量表部分。

局部變量表存放了編譯期可知的各種基本數(shù)據(jù)類型和對象引用和returnAddress類型(指向了一條字節(jié)碼指令的地址)嘶是。局部變量表所需的內(nèi)存空間在編譯期間完成分配钙勃,當進入一個方法時,這個方法需要在幀中分配多大的局部變量空間是完全確定的俊啼,在方法運行期間不會改變局部變量表的大小肺缕。

在Java虛擬機規(guī)范中,對這個區(qū)域規(guī)定了兩種異常狀況:如果線程請求的棧深度大于虛擬機所允許的深度授帕,將拋出StackOverflowError異常同木;如果虛擬機棧可以動態(tài)擴展(當前大部分的Java虛擬機都可動態(tài)擴展跛十,只不過Java虛擬機規(guī)范中也允許固定長度的虛擬機棧)彤路,如果擴展時無法申請到足夠的內(nèi)存,就會拋出OutOfMemoryError異常芥映。

本地方法棧

本地方法棧(線程私有)與虛擬機棧所發(fā)揮的作用是非常相似的洲尊,它們之間的區(qū)別不過是虛擬機棧為虛擬機執(zhí)行Java方法(也就是字節(jié)碼)服務(wù),而本地方法棧則為虛擬機使用到的Native方法服務(wù)奈偏。有的虛擬機(Hotspot)直接就把本地方法棧和虛擬機棧合二為一坞嘀。與虛擬機棧一樣,本地方法棧區(qū)域也會拋出StackOverflowError和OutOfMemoryError異常惊来。

對于大多數(shù)應(yīng)用來說丽涩,Java堆(也叫做"GC堆")是Java虛擬機所管理的內(nèi)存中最大的一塊。Java堆是被所有線程共享的一塊內(nèi)存區(qū)域裁蚁,在虛擬機啟動時創(chuàng)建矢渊。此內(nèi)存區(qū)域的唯一目的就是存放對象實例。

從內(nèi)存回收的角度來看枉证,由于現(xiàn)在收集器基本都采用分代收集算法矮男,所以Java堆中還可以細分為:新生代和老年代。從內(nèi)存分配的角度來看室谚,線程共享的Java堆中可能劃分出多個線程私有的分配緩沖區(qū)(TLAB)毡鉴,進一步劃分的目的是為了更好地回收內(nèi)存崔泵,或者更快地分配內(nèi)存。

根據(jù)Java虛擬機規(guī)范規(guī)定,Java堆可以處于物理上不連續(xù)的內(nèi)存空間中,只要邏輯上是連續(xù)的即可彪置。在實現(xiàn)時里伯,既可以實現(xiàn)成固定大小的,也可以是可擴展的崎弃,不過當前主流的虛擬機都是按照可擴展來實現(xiàn)的甘晤。如果在堆中沒有內(nèi)存完成實例分配,并且堆也無法再擴展時饲做,將會拋出OutOfMemoryError異常线婚。

方法區(qū)

方法區(qū)也是各個線程共享的內(nèi)存區(qū)域,它用于存儲已被虛擬機加載的類信息盆均、常量塞弊、靜態(tài)變量、即時編譯器編譯后的代碼等數(shù)據(jù)泪姨。雖然Java虛擬機規(guī)范把方法區(qū)描述為堆的一個邏輯部分游沿,但是它卻有一個別名叫做Non-Heap(非堆),目的是與Java堆區(qū)分開來肮砾。

對于習(xí)慣在HotSpot虛擬機上開發(fā)和部署程序的開發(fā)者來說诀黍,很多人都更愿意把方法區(qū)稱為"永久代"(Permanent Generation),本質(zhì)上兩者并不等價仗处,僅僅是因為HotSpot虛擬機的設(shè)計團隊選擇把GC分代收集擴展至方法區(qū)眯勾,或者說使用永久代來實現(xiàn)方法區(qū)而已,這樣Hotspot的垃圾收集器可以像管理Java堆一樣管理這部分內(nèi)存婆誓,能夠省去專門為方法區(qū)編寫內(nèi)存管理代碼的工作吃环。對于其他虛擬機(如BEA JRockit、IBMJ9等)來說是不存在永久代的概念的洋幻。使用永久代來實現(xiàn)方法區(qū)郁轻,現(xiàn)在看來并不是一個好主意,因為這樣更容易遇到內(nèi)存溢出問題鞋屈,而且有極少數(shù)方法(例如String.intern())會因這個原因?qū)е虏煌摂M機下有不同的表現(xiàn)范咨。所以在目前已經(jīng)發(fā)布的JDK1.7的HotSpot中,已經(jīng)把原本放在永久代的字符串常量池移出厂庇。

Java虛擬機規(guī)范對方法區(qū)的限制非常寬松渠啊,除了和Java堆一樣不需要連續(xù)的內(nèi)存和可以選擇固定大小或者可擴展外,還可以選擇不實現(xiàn)垃圾收集权旷。相對而言替蛉,垃圾收集行為在這個區(qū)域是比較少出現(xiàn)的贯溅,但并非數(shù)據(jù)進入了方法區(qū)就如永久代的名字一樣永久存在了。這區(qū)域的內(nèi)存回收目標主要是針對常量池的回收和對類型的卸載躲查。

根據(jù)Java虛擬機規(guī)范的規(guī)定它浅,當方法區(qū)無法滿足內(nèi)存分配需求時,將拋出OutOfMemoryError異常镣煮。

運行時常量池

運行時常量池是方法區(qū)的一部分姐霍。Class文件中除了有類的版本、字段典唇、方法镊折、接口等描述信息外,還有一項信息是常量池(叫做Class文件常量池)介衔,用于存放編譯期生成的各種字面量和符號引用恨胚,這部分內(nèi)容將在類加載后進入方法區(qū)的運行時常量池中存放炎咖。

運行時常量池相對于Class文件常量池的另外一個重要特征是具備動態(tài)性升熊,Java語言并不要求常量一定只有編譯期才能產(chǎn)生僚碎,也就是并非預(yù)置入Class文件中常量池的內(nèi)容才能進入方法區(qū)運行時常量池勺阐,運行期間也可能將新的常量放入池中渊抽,這種特性被開發(fā)人員利用的比較多的便是String類的intern()方法懒闷。JDK1.8版本中,String常量池已經(jīng)從方法區(qū)中的運行時常量池分離到堆中了玩焰。

既然運行時常量池是方法區(qū)的一部分芍锚,自然受到方法區(qū)內(nèi)存的限制蔓榄,當常量池無法再申請到內(nèi)存時會拋出OutOfMemoryError異常甥郑。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末荤西,一起剝皮案震驚了整個濱河市邪锌,隨后出現(xiàn)的幾起案子秃流,更是在濱河造成了極大的恐慌舶胀,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異基茵,居然都是意外死亡壳影,警方通過查閱死者的電腦和手機宴咧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進店門根灯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掺栅,“玉大人烙肺,你說我怎么就攤上這事桃笙≡踉裕” “怎么了丽猬?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長强饮。 經(jīng)常有香客問我由桌,道長,這世上最難降的妖魔是什么邮丰? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任行您,我火速辦了婚禮,結(jié)果婚禮上剪廉,老公的妹妹穿的比我還像新娘娃循。我一直安慰自己,他們只是感情好斗蒋,可當我...
    茶點故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布捌斧。 她就那樣靜靜地躺著,像睡著了一般泉沾。 火紅的嫁衣襯著肌膚如雪捞蚂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天跷究,我揣著相機與錄音姓迅,去河邊找鬼。 笑死俊马,一個胖子當著我的面吹牛丁存,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播潭袱,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼柱嫌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了屯换?” 一聲冷哼從身側(cè)響起编丘,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎彤悔,沒想到半個月后嘉抓,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡晕窑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年抑片,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片杨赤。...
    茶點故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡敞斋,死狀恐怖截汪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情植捎,我是刑警寧澤衙解,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站焰枢,受9級特大地震影響蚓峦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜济锄,卻給世界環(huán)境...
    茶點故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一暑椰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧荐绝,春花似錦一汽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至委造,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間均驶,已是汗流浹背昏兆。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留妇穴,地道東北人爬虱。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像腾它,于是被迫代替她去往敵國和親跑筝。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,494評論 2 348

推薦閱讀更多精彩內(nèi)容