JVM內(nèi)存模型 垃圾回收

Java最叼的地方就在于它的垃圾回收兔港,同時(shí)也是Java語言相比C++ 需要程序員手動(dòng)管理內(nèi)存的語言的最大優(yōu)勢(shì)乳绕,首先還是得先聊清楚JVM的內(nèi)存模型

JVM 內(nèi)存模型

image.png
image.png

注意鲸阔,java8及之后的JVM內(nèi)存模型與之前的有了區(qū)別疯趟,比較大的改動(dòng)就是移除了方法區(qū)晦譬,原本的方法區(qū)是屬于堆內(nèi)內(nèi)存,而元空間則直接使用的物理內(nèi)存习勤,也就是說元數(shù)據(jù)區(qū)的大小不再依賴于堆內(nèi)存大小踪栋。主要原因還是目前的程序中普遍存在很多運(yùn)行時(shí)生成的class對(duì)象,導(dǎo)致原本的方法區(qū)已經(jīng)不夠用图毕,容易觸發(fā) 方法區(qū)gc

  • 程序計(jì)數(shù)器
    • 一塊較小的內(nèi)存區(qū)域夷都,存儲(chǔ)線程信息。主要是為了線程切換后能恢復(fù)到正確的執(zhí)行位置予颤,每個(gè)線程都有一個(gè)獨(dú)立的程序計(jì)數(shù)器囤官,互不干擾,唯一一個(gè)不會(huì)拋出 OOM異常的區(qū)域
  • 虛擬機(jī)棧
    • 與程序計(jì)數(shù)器類似蛤虐,也是線程私有党饮。虛擬機(jī)棧的內(nèi)存模型非常重要 ,理解java的線程模型務(wù)必要理解虛擬機(jī)棧的內(nèi)存模型驳庭。這里簡單介紹一下劫谅,虛擬機(jī)棧描述的是Java方法執(zhí)行的內(nèi)存模型,每個(gè)方法在執(zhí)行的時(shí)候都會(huì)創(chuàng)建一個(gè)棧幀(stack frame)用來存儲(chǔ) 局部變量表嚷掠,操作數(shù)棧捏检,動(dòng)態(tài)鏈接,方法出口等信息不皆。局部變量表用于存儲(chǔ) 基本數(shù)據(jù)類型贯城,對(duì)象引用(不絕對(duì),開啟逃逸分析的話霹娄,也會(huì)在棧上分配內(nèi)存)
    • 會(huì)拋出兩種異常
      • 超過虛擬機(jī)規(guī)定的最大棧深度能犯,拋出 StackOverflowError
      • OutOfMemryError stack
  • 本地方法棧
    • 與虛擬機(jī)棧類似,僅僅是執(zhí)行的是Native方法
    • 堆是java內(nèi)存空間最大的一塊犬耻,后面也會(huì)著重畫下重點(diǎn)踩晶,并且堆是線程不安全的,每個(gè)線程公用堆內(nèi)存枕磁,幾乎所有的對(duì)象都在堆上分配內(nèi)存渡蜻,但也不絕對(duì)(比如上面提到的棧上分配)。當(dāng)前主流的虛擬機(jī)基本都把堆劃分為兩個(gè)區(qū)域 1.新生代 2.老年代 其中新生代计济,又可分為 Eden茸苇,F(xiàn)rom Survivor ,To Survivor垃圾回收也是主要在這快區(qū)域
    • 會(huì)拋出OutOfMemryError Heap space
  • 元空間
    • 與Java堆一樣沦寂,也是線程共享的區(qū)域学密。主要存儲(chǔ)虛擬機(jī)加載的類信息,在java7之前我們又把它叫做方法區(qū)传藏,當(dāng)時(shí)常量池也存在這里(現(xiàn)在已經(jīng)在堆內(nèi)存中)腻暮。垃圾收集在這個(gè)區(qū)域比較少出現(xiàn)
    • 會(huì)拋出OutOfMemryError PermGen space

對(duì)象的內(nèi)存結(jié)構(gòu)

這里主要介紹下對(duì)象頭信息<br />這里要理解的是彤守,對(duì)象頭是一個(gè)可變的長度,并且存的數(shù)據(jù)再每種狀態(tài)下都是不同的哭靖,下表詳列了每種狀態(tài)下對(duì)象頭所存儲(chǔ)的信息<br />

image.png
image.png

這里跟java鎖升級(jí)優(yōu)化有關(guān)

垃圾回收

著重講一下垃圾回收<br />在講垃圾回收之前遗增,先說一下什么樣的對(duì)象會(huì)被垃圾回收?<br />目前主要有兩種方法判斷 對(duì)象是不是可被回收

  • 引用計(jì)數(shù)
  • 可達(dá)性分析

引用計(jì)數(shù)比較好理解款青,每有一個(gè)對(duì)象被持有引用加1,當(dāng)引用計(jì)數(shù)為0時(shí)霍狰,就通知垃圾收集器回收抡草。這樣子的算法比較簡單,但有循環(huán)引用的問題蔗坯,循環(huán)應(yīng)用的對(duì)象并不會(huì)被回收康震。實(shí)際上JVM也不是用的引用計(jì)數(shù)法

可達(dá)性分析理解起來相對(duì)抽象一下,但是目前主流的虛擬機(jī)都是用的可達(dá)性分析算法宾濒。算法的核心就是 挑選 GC Root 做可達(dá)性分析腿短,當(dāng)GC Root不可達(dá)該對(duì)象時(shí),說明該對(duì)象要被回收绘梦,所以該算發(fā)的核心就是選擇合適的GC Root 橘忱。可用作GC Root的對(duì)象主要有

  • 虛擬機(jī)棧中引用的對(duì)象
  • 方法區(qū)中靜態(tài)屬性引用的對(duì)象
  • 常量引用的對(duì)象
  • 本地方法棧應(yīng)用的對(duì)象

引用分為三種類型

  • 強(qiáng)引用 不用多說
  • 軟引用
    • 系統(tǒng)將要發(fā)生內(nèi)存溢出之前會(huì)被回收
  • 弱引用
    • 只要垃圾回收器 工作了就會(huì)被回收
  • 虛引用
    • 沒什么用卸奉。钝诚。。

垃圾收集算法

標(biāo)記清除

顧名思義榄棵,就是標(biāo)記了再清除<br />缺點(diǎn):效率低 會(huì)產(chǎn)生內(nèi)存碎片

復(fù)制清除

為了解決效率問題凝颇,引出了復(fù)制算法。主要原理就是將內(nèi)存分為兩塊疹鳄,每次只使用一塊拧略,當(dāng)一塊用完了,就將還存活著的對(duì)象復(fù)制到另一塊內(nèi)存中瘪弓,然后將剩下的全部清除垫蛆。<br />這個(gè)算法優(yōu)點(diǎn)就是 不會(huì)產(chǎn)生內(nèi)存碎片,效率高腺怯,但是空間利用率不高(新生代用的就是復(fù)制算法月褥,不同的是新生代將內(nèi)存分為3塊 Eden,F(xiàn)rom Survivor 瓢喉,To Survivor)比例默認(rèn)是 8:1:1

標(biāo)記整理

標(biāo)記整理算法和標(biāo)記清除類型宁赤,不同的是 清除之后,會(huì)進(jìn)行內(nèi)存整理栓票,以減少內(nèi)存碎片

分代收集

分代收集嚴(yán)格來說并不是一種收集算法决左,僅僅只是一種思想愕够。它把內(nèi)存分成各個(gè)區(qū)域,每個(gè)區(qū)域都使用合適的算法去做垃圾回收佛猛,如新生代使用復(fù)制算法惑芭,老年代使用標(biāo)記整理<br /><br />

垃圾收集器

Serial 收集器

新生代單線程收集器(復(fù)制清除算法),收集的時(shí)候會(huì) stop the world继找,一般都不怎么用了遂跟,除了在一些 Java桌面應(yīng)用的CLient端還有用外

Parnew 收集器

新生代多線程收集器,serial 收集器的多線程版本婴渡,其他跟serial收集器完全一樣幻锁。清理的時(shí)候也會(huì) stop the world。一般用來搭配使用 CMS 收集器

Parallel Scavenge 收集器

和 Parnew 收集器非常相似边臼,都是新生代多線程收集器哄尔,但是Parallel Scavenge與其他收集器的關(guān)注點(diǎn)不一樣,它不關(guān)注 停頓時(shí)間點(diǎn)(stop the world)柠并,而關(guān)注吞吐量

Serial Old 收集器

serial 收集器的老年代版本岭接,單線程收集器,使用標(biāo)記整理算法臼予,不怎么用鸣戴。用來做CMS的后備

CMS

基于標(biāo)記清除粘拾。CMS 是目前公司使用的 老年代收集器葵擎,也是大多數(shù)Web應(yīng)用所采用的收集器。原因在于CMS收集器是以最短回收停頓時(shí)間為目前的收集器半哟,對(duì)于用戶體驗(yàn)來說會(huì)比較友好。<br />CMS 收集器包含四個(gè)步驟

  • 初始標(biāo)記 (stop the world 但是時(shí)間很短)
  • 并發(fā)標(biāo)記
  • 重新標(biāo)記 stop the world
  • 并發(fā)清除

缺點(diǎn)

  • 對(duì)CPU敏感
  • 無法處理浮動(dòng)垃圾几缭,重新標(biāo)記的時(shí)候也會(huì)產(chǎn)生垃圾
  • 內(nèi)存碎片 標(biāo)記清除算法的通病

G1收集器

目前最屌的了

  • 停頓時(shí)間力求最短
  • 標(biāo)記整理
  • 不需要配合其他收集器年栓,一個(gè)就可以搞定 新生代 和老年代
  • 可預(yù)測(cè)的停頓 (某抓??這是)

回收策略

年輕代 MinorGC<br />老年代 MajorGC<br />Full Gc 會(huì)至少伴隨一次 MinorGC

  • 大對(duì)象直接進(jìn)入老年代
  • 長期存活對(duì)象進(jìn)入老年代 (默認(rèn)是15次 -XX:MaxTenuingThrehold = 15 設(shè)置)
  • 空間分配擔(dān)保
    • 在發(fā)生MinorGC前备禀,虛擬機(jī)會(huì)檢查老年代最大用連續(xù)空間是否大于新生代所有對(duì)象總空間洲拇,如果這個(gè)條件成立,則可以確保這次MinorGC是安全的曲尸。如果不成立虛擬機(jī)則會(huì)檢查 HandelPromotionFailure 設(shè)置值是否允許擔(dān)保失敗赋续。如果允許則繼續(xù)檢查老年代最大可用空間是否大于歷次新生代晉升到老年代對(duì)象的平均大小,如果大于队腐,則盡管有風(fēng)險(xiǎn)也會(huì)進(jìn)行一次MinorGC。如果小于或則不允許擔(dān)保失敗奏篙,則直接進(jìn)行 Full GC

<br />

虛擬機(jī)監(jiān)測(cè)工具

jps

  • jps -v 輸出啟動(dòng)詳細(xì)信息
  • jps -l 輸出主類全名
  • jps -m 輸出main函數(shù)
  • jps -q 輸出 進(jìn)程id

下面的命令都會(huì)用到 jps 查出的進(jìn)程id(vmid)

jstat

用于監(jiān)視虛擬機(jī)運(yùn)行狀態(tài)

  • jstat -class vmid 監(jiān)測(cè)類裝載耗時(shí)
  • jstat -gc vmid 監(jiān)測(cè)堆狀況 GC時(shí)間等

jinfo

查詢配置信息

jmap

生成內(nèi)存快照

  • jmap -dump:format=b,file=heapdump.phrof vmid 導(dǎo)出dump文件柴淘,也可以加系統(tǒng)參數(shù) -XX:+HeapDumpOnOutOfMemoryError或則通過-XX:+HeapDumpOnCtrlBreak在程序運(yùn)行時(shí)按Crtl+Break生成 dump文件

jhat

分析 dump文件的工具,不過有點(diǎn)難用

jstack

打印線程堆棧

  • jstack vmid

一般分析堆棧異常時(shí)用到秘通,常用的命令組合是

1.找出占用CPU占用最高的線程id
top -bn1 -H -p <pid>
2.將找的線程id轉(zhuǎn)換成16進(jìn)制
printf "%x \n" <tid>
3.通過jstack定位問題代碼
jstack -l <pid> | grep -A10 <tid>
  • visualvm

這個(gè)比較好用为严,也很強(qiáng)大

有些時(shí)候,這些工具真的用不到肺稀。但并不代表第股,你不需要去了解這些

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市话原,隨后出現(xiàn)的幾起案子夕吻,更是在濱河造成了極大的恐慌,老刑警劉巖繁仁,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涉馅,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡黄虱,警方通過查閱死者的電腦和手機(jī)稚矿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捻浦,“玉大人晤揣,你說我怎么就攤上這事≈觳樱” “怎么了昧识?”我有些...
    開封第一講書人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長盗扒。 經(jīng)常有香客問我滞诺,道長形导,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任习霹,我火速辦了婚禮朵耕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘淋叶。我一直安慰自己阎曹,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開白布煞檩。 她就那樣靜靜地躺著处嫌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪斟湃。 梳的紋絲不亂的頭發(fā)上熏迹,一...
    開封第一講書人閱讀 51,578評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音凝赛,去河邊找鬼注暗。 笑死燃异,一個(gè)胖子當(dāng)著我的面吹牛滚局,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播淌友,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼毙沾,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼骗卜!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起左胞,我...
    開封第一講書人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤寇仓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后烤宙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體焚刺,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年门烂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了乳愉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡屯远,死狀恐怖蔓姚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情慨丐,我是刑警寧澤坡脐,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站房揭,受9級(jí)特大地震影響备闲,放射性物質(zhì)發(fā)生泄漏晌端。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一恬砂、第九天 我趴在偏房一處隱蔽的房頂上張望咧纠。 院中可真熱鬧,春花似錦泻骤、人聲如沸漆羔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽演痒。三九已至,卻和暖如春趋惨,著一層夾襖步出監(jiān)牢的瞬間鸟顺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來泰國打工器虾, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留讯嫂,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓曾撤,卻偏偏與公主長得像端姚,于是被迫代替她去往敵國和親晕粪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子挤悉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355

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