深入理解java虛擬機(一)--自動內存管理機制

一宝恶、java虛擬機運行時數據取

1涕俗、程序計數器(Program Counter Register)

? ? ? 程序計數器是一塊較小的內存,他可以看作是當前線程所執(zhí)行的字節(jié)碼的行號指示器欧芽。在虛擬機的概念模型里浓体,字節(jié)碼解釋器工作時就是通過改變這個這個計數器的值來選取下一條需要執(zhí)行的字節(jié)碼指令,分支泣刹、循環(huán)、跳轉犀被、異常處理椅您、線程恢復等基礎功能都需要依賴這個計數器來完成。由于java虛擬機的多線程是通過線程輪流切換并分配處理器執(zhí)行時間的方式來實現的寡键,在任何一個時刻掀泳,一個處理器一個內核只會執(zhí)行一條線程中的指令。因此每條線程都需要有一個獨立的程序計數器西轩,各條線程之間計數器互不影響员舵,獨立存儲,這類內存為“線程私有”內存藕畔。

2马僻、Java虛擬機棧(Java Virtual Machine Stacks)

? ? Java虛擬機棧也是線程私有的,生命周期與線程相同注服。其描述的是Java方法執(zhí)行的內存模型:每個方法在執(zhí)行的同時都會創(chuàng)建一個棧幀(Stack Frame)用于存儲局部變量表韭邓、操作數棧、動態(tài)鏈接溶弟、方法出口等信息女淑。每一個方法從調用直至執(zhí)行完成的過程,就對應著一個棧幀在虛擬機棧中入棧到出棧的過程辜御。

3鸭你、本地方法棧(Native Method Stack)

? ? ? 與虛擬機棧很相似,區(qū)別:虛擬機棧為虛擬機執(zhí)行java方法服務,本地方法棧是為虛擬機使用到的Native方法服務袱巨。

4阁谆、Java堆

? ? ? Java堆(Java Heap)是java虛擬機所管理的內存中最大的一塊。Java堆是被所有線程共享的一塊內存區(qū)域瓣窄,在虛擬機啟動時創(chuàng)建笛厦。此內存區(qū)域的唯一目的就是存放對象實例,幾乎所有的對象實例都在這里分配內存俺夕。Java堆是垃圾收集器管理的主要區(qū)域裳凸。Java堆中還可以細分為:新生代和老年代;再細一點的有:Eden空間劝贸,From Survivor空間姨谷,To Survivor空間等。

5映九、方法區(qū)(Method Area)

? ? 與Java堆一樣梦湘,是各個線程共享的內存區(qū)域,它用于存儲已被虛擬機加載的類消息件甥、常量捌议、靜態(tài)變量、即時編譯器編譯后的代碼等數據引有。

6瓣颅、運行時常量池(Runtime Constant Pool)

? ? 這是方法區(qū)的一部分。Class文件中除了有類的版本譬正、字段宫补、方法、接口等描述信息外曾我,還有是常量池(Constant Pool Table)粉怕,用于存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載后進入方法區(qū)的運行時常量池中存放抒巢。

7贫贝、直接內存(Direct Memory)

? ? 本機物理機內存。

二蛉谜、探討HotSpot虛擬機在Java堆中對象分配平酿、布局和訪問的過程

1、對象的創(chuàng)建

? ? ? Object obj=new Object();

? ? ? jvm遇到一條new指令時悦陋,首先會去檢查這個指令的參數是否能在常量池中定位到一個類的符號蜈彼,并且檢查這個符號引用代表的類是否已被加載、解析和初始化過俺驶。如果沒有幸逆,那么必須先執(zhí)行相應的類加載過程棍辕。

? ? ? 在類加載檢查通過后,接下來jvm將為新生對象分配內存还绘,并且對象所需的內存已經確定了楚昭。如果java堆中內存是絕對規(guī)整的,則用“指針碰撞”分配方式拍顷。如果java堆中的內存并不是絕對規(guī)整的抚太,已使用的內存和空閑的內存相互交錯,jvm就必須維護一個列表昔案,記錄上哪些內存塊是可用的尿贫,在分配的時候從列表中找到一塊足夠大的空間規(guī)劃給對象實例,并更新列表上的記錄踏揣。這種分配方式叫“空閑列表”庆亡。java堆是否規(guī)整決定了內存的分配方式,而java堆規(guī)整與否捞稿,由所采用的垃圾收集器是否帶有壓縮整理功能決定的又谋。使用Serial、ParNew 等帶Compact過程的收集器時娱局,系統(tǒng)采用指針碰撞分配彰亥,而使用CMS這種基于Mark-Sweep算法的收集器時,通常采用空閑列表衰齐。

? ? ? 分配空間之外剩愧,我們還應該考慮是否線程安全,而jvm有兩種解決方案娇斩,一種是對分配內存空間的動作進行同步處理---實際上jvm采用CAS配上失敗重試的方式保證更新操作的原子性;另一種是把內存分配的動作按照線程劃分在不同的空間之中進行穴翩,即每個線程在Java堆中預先分配一小塊內存犬第,稱為本地線程分配緩沖(Thread Local Allocation Buffer,TLAB)

? ? ? 內存分配完后,虛擬機需要將分配到內存空間都初始化為零值芒帕。

? ? ? 以上工作都完成之后歉嗓,從jvm的視角來看,一個新的對象已經產生了背蟆,但是從java來看鉴分,對象創(chuàng)建才剛剛開始,----方法還沒有執(zhí)行,所有的字段都為零带膀。執(zhí)行完init方法后志珍,這樣一個真正的對象才算完全產生出來。

2垛叨、對象的內存布局

? ? 在HotSpot虛擬機中伦糯,對象在內存中存儲的布局可以分為3塊區(qū)域:對象頭(Header)、實例數據(Instance Data)和對齊填充(Padding)。

? ? ? HotSpot虛擬機的對象頭包括兩部分信息敛纲,第一部分用于存儲對象自身的運行時數據喂击,如哈希碼(HashCode),GC分代年齡淤翔、鎖狀態(tài)標志翰绊、線程持有的鎖、偏向線程ID旁壮、偏向時間戳等监嗜。另一部分是類型指針,即對象指向它的類元數據的指針寡具,虛擬機通過這個指針來確定這個對象是哪個類的實例秤茅。

? ? ? 實例數據部分是對象真正存儲的有效信息,也是在程序代碼中所定義的各種類型的字段內容童叠。

? ? ? 第三部分對其填充并不是必然存在的框喳,也沒有特別的含義,它僅僅起著占位符的作用厦坛。

3五垮、 對象的訪問定位

? ? ? java程序需要通過棧上的reference數據來操作堆上的具體對象。目前主流的訪問方式有使用句柄和直接指針兩種杜秸。

? ? ? 1放仗、句柄訪問,java堆中將會規(guī)劃分出一塊內存來作為句柄池撬碟,reference中存儲的就是對象的句柄地址诞挨,而句柄中包含了對象實例數據與類型數據各自的具體地址信息。如圖:

? ? ? 2呢蛤、指針訪問惶傻,java堆對象的布局中就必須考慮如何放置訪問類型數據的相關信息,而reference中存儲的直接就是對象地址其障。如圖:


三银室、OutOfMemoryError異常

1、Java堆異常

? ? ? Java用于存儲對象實例励翼。

? ? ? 通過參數 --XX:+HeapDumpOnOutOfMemoryError蜈敢,異常時可以Dump出當前內存堆轉儲快照以便分析。-Xms20m:設置java堆最小內存汽抚, -Xmx20m:設置Java堆最大內存

eg:

/**

* VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError

**/

public class HeapOOM{

? ? ? static class OOMObject{

? ? ? }

? ? ? public static void main(){

? ? ? ? ? List list =new ArrayList();

? ? ? ? ? while(true){

? ? ? ? ? ? ? list.add(new OOMObject());

? ? ? ? ? ? }

? ? ? }

}

2抓狭、虛擬機棧和本地方法棧溢出

? ? -Xss 參數控制棧內存的大小,eg:-Xss128k造烁。結果拋出StackOverFlowError異常辐宾。

3狱从、方法區(qū)和運行時常量池溢出

? ? ? 可以通過 -XX:PermSize和 -XX:MaxPermSize,限制方法區(qū)大小叠纹。

eg:

? ? ? -XX:PermSize=10M? -XX:MaxPermSize=10M

4季研、本機直接內存溢出

? ? ? DirectMemory容量可以通過 -XX:MaxDirectMemorySize指定,如果不指定誉察,則默認與Java堆最大值(-Xmx指定)一樣与涡。

本文來自于《深入Java虛擬機-JVM高級特性與最佳實踐》---周志明。如果侵權持偏,請聯系作者刪除驼卖。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市鸿秆,隨后出現的幾起案子酌畜,更是在濱河造成了極大的恐慌,老刑警劉巖卿叽,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桥胞,死亡現場離奇詭異,居然都是意外死亡考婴,警方通過查閱死者的電腦和手機贩虾,發(fā)現死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沥阱,“玉大人缎罢,你說我怎么就攤上這事】忌迹” “怎么了策精?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長崇棠。 經常有香客問我咽袜,道長,這世上最難降的妖魔是什么易茬? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮及老,結果婚禮上抽莱,老公的妹妹穿的比我還像新娘。我一直安慰自己骄恶,他們只是感情好食铐,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著僧鲁,像睡著了一般虐呻。 火紅的嫁衣襯著肌膚如雪象泵。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天斟叼,我揣著相機與錄音偶惠,去河邊找鬼。 笑死朗涩,一個胖子當著我的面吹牛忽孽,可吹牛的內容都是我干的。 我是一名探鬼主播谢床,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼兄一,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了识腿?” 一聲冷哼從身側響起出革,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎渡讼,沒想到半個月后骂束,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡硝全,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年栖雾,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伟众。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡析藕,死狀恐怖,靈堂內的尸體忽然破棺而出凳厢,到底是詐尸還是另有隱情账胧,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布先紫,位于F島的核電站治泥,受9級特大地震影響,放射性物質發(fā)生泄漏遮精。R本人自食惡果不足惜居夹,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望本冲。 院中可真熱鬧准脂,春花似錦、人聲如沸檬洞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽添怔。三九已至湾戳,卻和暖如春贤旷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背砾脑。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工幼驶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拦止。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓县遣,卻偏偏與公主長得像,于是被迫代替她去往敵國和親汹族。 傳聞我的和親對象是個殘疾皇子萧求,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內容