深入理解java虛擬機(一)java內(nèi)存區(qū)域與內(nèi)存溢出異常

寫在前面:為了更加深入的了解java虛擬機便斥,就看了一下《深入理解java虛擬機》這本書国夜,一方面為了總結(jié)一下自己的認(rèn)識米愿,另一方面就是想與各位分享厦凤,如果有什么不對的地方,歡迎指正

在進行java開發(fā)的時候育苟,開發(fā)人員一般都不需要關(guān)注內(nèi)存的請求较鼓,釋放等過程,那么jvm是怎樣幫我們完成的呢
深入理解java虛擬機(二)垃圾收集器與內(nèi)存分配策略

java內(nèi)存區(qū)域與內(nèi)存溢出異常

1违柏、運行時數(shù)據(jù)區(qū)

  • 程序計數(shù)器(Program Counter Register)
    用于保存程序的當(dāng)前執(zhí)行的指令地址博烂,當(dāng)cpu執(zhí)行指令時候,會從程序計數(shù)器中獲取當(dāng)前指定指令所在位置的存單元的地址漱竖,然后根據(jù)地址獲取到指令禽篱,執(zhí)行,然后指向下一條馍惹,循環(huán)直至結(jié)束躺率,jvm是通過多線程來完成指令的,為了線程切換后能夠恢復(fù)之前的狀態(tài)万矾,所以每個線程都有私有的程序計數(shù)器悼吱,唯一一個不會發(fā)生OutOfMemoryError的地方
  • Java棧(VM Stack)
    java棧中存儲的是棧幀,每個棧幀對應(yīng)一個被調(diào)用的方法良狈,棧幀中包含局部變量表(七大數(shù)據(jù)類型后添,對象引用,)们颜,操作數(shù)棧吕朵,動態(tài)鏈接猎醇,方法出口等,努溃,指向當(dāng)前類所屬的常量池的引用硫嘶,和方法返回地址,當(dāng)線程調(diào)用一個方法時梧税,會創(chuàng)建對應(yīng)的棧幀沦疾,然后進棧,執(zhí)行完成之后第队,出棧哮塞,所以說運行的方法在棧頂,遞歸容易出現(xiàn)內(nèi)存溢出的現(xiàn)象凳谦,棧不用程序員自己管理內(nèi)存 (java有自己的垃圾回收機制)忆畅,棧區(qū)是線程私有的,因為每個線程執(zhí)行的方法不同尸执,容易混家凯,

棧中的異常
當(dāng)線程請求棧深度大于虛擬機所允許的深度的時候,會拋出stackOverflowError異常如失,虛擬機棸砘澹可以動態(tài)擴展,如果在擴展的時候無法申請到足夠的內(nèi)存褪贵,就會拋出outofmemoryError異常

  • 本地方法棧(Native Method Stack)
    可與java棧放在一起說掂之,區(qū)別就是,本地運行的是nactive的方法,也會發(fā)生oom的異常
  • 方法區(qū)(Method Area)
    所有線程共享脆丁,存儲已被虛擬機加載的類信息世舰,常量,靜態(tài)變量偎快,即時編譯器編譯后的代碼等數(shù)據(jù)冯乘。這個區(qū)域的內(nèi)存回收目標(biāo)主要是針對常量池的對象的回收和對類型的卸載。 也會拋出oom的異常
  • 堆(Heap)
    JAVA 堆晒夹,也稱 GC 堆,所有線程共享姊氓,存放對象的實例和數(shù)組丐怯, JAVA 堆是垃圾收集器管理的主要區(qū)域。當(dāng)申請內(nèi)存不夠的時候也會拋出oom異常
  • 運行時常量池
    屬于方法區(qū)翔横,Class文件的信息读跷,存放編譯期生成的各種字面量和符號引用,這部分內(nèi)容將在類加載后進入方法區(qū)的運行時常量池禾唁,也會有oom異常
  • 直接內(nèi)存
    并不是虛擬機運行時數(shù)據(jù)區(qū)的一部分效览,也不是java虛擬機規(guī)范中定義的內(nèi)存區(qū)域无切,引入NIO之后,引入了一種基于通道(channel)與緩沖區(qū)(buffer)的IO方式丐枉,它可以使用native函數(shù)庫直接分配堆外內(nèi)存哆键,然后通過一個存儲在java堆中的DirectByteBuffer對象作為這塊內(nèi)存的引用進行操作,這樣能在一些場景中提高性能瘦锹,因為避免了在java堆和native堆中來回復(fù)制數(shù)據(jù)籍嘹。也有oom異常

2、hotspot虛擬機對象探秘

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

當(dāng)在new一個對象的時候辱士,首先會去常量池(存放類的信息,屬于方法區(qū))定位這個類的信息听绳,查看是否有加載這個類颂碘,如果沒有這個類,先執(zhí)行類加載椅挣,類加載完成之后凭涂,給這個對象在堆中分配內(nèi)存,對象的內(nèi)存大小在類加載完成之后就會確定贴妻,假如這個堆中的內(nèi)存是整齊的切油,占用的在一邊,空閑的在一邊名惩,中間放著一個指針作為分界點的指示器澎胡,分配內(nèi)存就是將指針向空閑區(qū)域移動對象內(nèi)存大小,這種分配叫做指針碰撞娩鹉,假如堆中的內(nèi)存不是整齊的攻谁,那么虛擬機就會維護一個列表,用于記錄內(nèi)存的使用情況弯予,在分配內(nèi)存的時候戚宦,會在列表中尋找一個足夠大的內(nèi)存分配給這個對象,這種方式叫做空閑列表锈嫩,使用哪種分配方式由java虛擬機堆是否規(guī)整決定受楼,是否規(guī)整由采用的垃圾采集器決定,使用serial呼寸,parnew等帶有compact過程的收集器時候艳汽,系統(tǒng)采用的分配算法是指針碰撞,使用cms這種基于mark-sweep算法的收集器的時候对雪,采用空閑列表河狐,

new對象是很頻繁的事,在并發(fā)下不是安全的,再給a分配內(nèi)存的時候馋艺,指針還未修改栅干,對象b使用l這個指針分配內(nèi)存,解決方案:一種是對分配內(nèi)存空間的動作進行同步處理捐祠,虛擬機采用CAS配上失敗重試的方式保證更新操作的原子性碱鳞,另一種是把內(nèi)存分配的動作按照線程劃分在不同的空間之中進行,

內(nèi)存分配完成之后雏赦,虛擬機需要將分配到的內(nèi)存空間都初始化為0劫笙,不包括對象頭,虛擬機對對象進行必要的設(shè)置星岗,例如這個對象是哪個類的實例填大,如何得到類的元數(shù)據(jù)信息,對象的哈希嗎俏橘,對象的GC分代年齡信息等允华,這些信息放在對象的對象頭中

2、對象的內(nèi)存分配

對象在內(nèi)存中存儲寥掐,分為三個部分靴寂,對象頭,實例數(shù)據(jù)召耘,對齊方式

  • 對象頭
    對象頭分為兩個部分百炬,一是存儲對象的運行時數(shù)據(jù),GC年齡污它,哈希碼剖踊,鎖狀態(tài)標(biāo)志,線程持有的鎖衫贬,偏向線程ID德澈,偏向時間戳等,另一部分是存放他的類元數(shù)據(jù)指針固惯,虛擬機通過這個確定這個實例是哪個類的實例梆造,也并不是所有的虛擬機實現(xiàn)都必須在對象數(shù)據(jù)上保留類型指針,如果對象是數(shù)組葬毫,對象頭中還需要有一塊記錄數(shù)組長度的數(shù)據(jù)镇辉,因為虛擬機可以通過普通java對象的元數(shù)據(jù)確定java對象的大小,但是從數(shù)組的元數(shù)據(jù)中卻無法確定數(shù)組的大小
  • 實例數(shù)據(jù)
    用于存儲對象真正的信息供常,定義的各種字段摊聋,相同寬度的字段會被分配到一起,所以子類和父類的字段有可能會在一起
  • 對齊填充
    由于對象的大小必須是8的倍數(shù)栈暇,對象頭正好是8的倍數(shù),而實例數(shù)據(jù)并不一定箍镜,所以需要這個來站位源祈,補充

3煎源、對象的訪問定位

如何訪問到堆中的實例呢,在棧中存放著實例的引用reference香缺,有兩種方式手销,一種是句柄,一種是指針引用

  • 句柄
    在堆中會分配一個句柄池图张,存放實例的地址锋拖,而reference中存放的就是對象的句柄地址,


    image.png
  • 指針訪問
    reference直接存儲對象在堆中的地址
    句柄的好處祸轮,當(dāng)實例需要被挪位置的時候兽埃,垃圾回收的時候會有,我們只需要改變句柄中的對象地址适袜,不要改引用柄错, 而使用指針訪問,就需要改變reference苦酱,但是好處是少了一次指針尋找售貌,速度快


    image.png

3、實戰(zhàn)OutOfMemoryError

1疫萤、堆內(nèi)存溢出

Heap

當(dāng)我們指定了一定大小的堆內(nèi)存颂跨,并一直new 對象,就會發(fā)生堆內(nèi)存溢出的錯誤扯饶,因為對象不能被回收恒削,內(nèi)存不夠

2、Stack Overflow

Stack Overflow

當(dāng)我們不停的遞歸調(diào)用方法帝际,造成棧的深度不夠蔓同,即會發(fā)生此錯誤

更多內(nèi)容請看后續(xù),
QQ交流群:552113611

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蹲诀,一起剝皮案震驚了整個濱河市斑粱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌脯爪,老刑警劉巖则北,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異痕慢,居然都是意外死亡尚揣,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門掖举,熙熙樓的掌柜王于貴愁眉苦臉地迎上來快骗,“玉大人,你說我怎么就攤上這事》嚼海” “怎么了名秀?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長藕溅。 經(jīng)常有香客問我匕得,道長,這世上最難降的妖魔是什么巾表? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任汁掠,我火速辦了婚禮,結(jié)果婚禮上集币,老公的妹妹穿的比我還像新娘考阱。我一直安慰自己,他們只是感情好惠猿,可當(dāng)我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布羔砾。 她就那樣靜靜地躺著,像睡著了一般偶妖。 火紅的嫁衣襯著肌膚如雪姜凄。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天趾访,我揣著相機與錄音态秧,去河邊找鬼。 笑死扼鞋,一個胖子當(dāng)著我的面吹牛申鱼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播云头,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼捐友,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了溃槐?” 一聲冷哼從身側(cè)響起匣砖,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎昏滴,沒想到半個月后猴鲫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡谣殊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年拂共,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姻几。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡宜狐,死狀恐怖势告,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情肌厨,我是刑警寧澤培慌,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布豁陆,位于F島的核電站柑爸,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏盒音。R本人自食惡果不足惜表鳍,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望祥诽。 院中可真熱鬧譬圣,春花似錦、人聲如沸雄坪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽维哈。三九已至绳姨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間阔挠,已是汗流浹背飘庄。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留购撼,地道東北人跪削。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像迂求,于是被迫代替她去往敵國和親碾盐。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,925評論 2 344

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