JVM內存模型 垃圾回收

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

JVM 內存模型

image.png
image.png

注意,java8及之后的JVM內存模型與之前的有了區(qū)別,比較大的改動就是移除了方法區(qū),原本的方法區(qū)是屬于堆內內存,而元空間則直接使用的物理內存,也就是說元數據區(qū)的大小不再依賴于堆內存大小。主要原因還是目前的程序中普遍存在很多運行時生成的class對象,導致原本的方法區(qū)已經不夠用,容易觸發(fā) 方法區(qū)gc

  • 程序計數器
    • 一塊較小的內存區(qū)域,存儲線程信息。主要是為了線程切換后能恢復到正確的執(zhí)行位置,每個線程都有一個獨立的程序計數器,互不干擾,唯一一個不會拋出 OOM異常的區(qū)域
  • 虛擬機棧
    • 與程序計數器類似,也是線程私有。虛擬機棧的內存模型非常重要 ,理解java的線程模型務必要理解虛擬機棧的內存模型。這里簡單介紹一下,虛擬機棧描述的是Java方法執(zhí)行的內存模型,每個方法在執(zhí)行的時候都會創(chuàng)建一個棧幀(stack frame)用來存儲 局部變量表,操作數棧,動態(tài)鏈接,方法出口等信息。局部變量表用于存儲 基本數據類型,對象引用(不絕對,開啟逃逸分析的話,也會在棧上分配內存)
    • 會拋出兩種異常
      • 超過虛擬機規(guī)定的最大棧深度,拋出 StackOverflowError
      • OutOfMemryError stack
  • 本地方法棧
    • 與虛擬機棧類似,僅僅是執(zhí)行的是Native方法
    • 堆是java內存空間最大的一塊,后面也會著重畫下重點,并且堆是線程不安全的,每個線程公用堆內存,幾乎所有的對象都在堆上分配內存,但也不絕對(比如上面提到的棧上分配)。當前主流的虛擬機基本都把堆劃分為兩個區(qū)域 1.新生代 2.老年代 其中新生代,又可分為 Eden,From Survivor ,To Survivor垃圾回收也是主要在這快區(qū)域
    • 會拋出OutOfMemryError Heap space
  • 元空間
    • 與Java堆一樣,也是線程共享的區(qū)域。主要存儲虛擬機加載的類信息,在java7之前我們又把它叫做方法區(qū),當時常量池也存在這里(現在已經在堆內存中)。垃圾收集在這個區(qū)域比較少出現
    • 會拋出OutOfMemryError PermGen space

對象的內存結構

這里主要介紹下對象頭信息<br />這里要理解的是,對象頭是一個可變的長度,并且存的數據再每種狀態(tài)下都是不同的,下表詳列了每種狀態(tài)下對象頭所存儲的信息<br />

image.png
image.png

這里跟java鎖升級優(yōu)化有關

垃圾回收

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

  • 引用計數
  • 可達性分析

引用計數比較好理解,每有一個對象被持有引用加1,當引用計數為0時,就通知垃圾收集器回收。這樣子的算法比較簡單,但有循環(huán)引用的問題,循環(huán)應用的對象并不會被回收。實際上JVM也不是用的引用計數法

可達性分析理解起來相對抽象一下,但是目前主流的虛擬機都是用的可達性分析算法。算法的核心就是 挑選 GC Root 做可達性分析,當GC Root不可達該對象時,說明該對象要被回收,所以該算發(fā)的核心就是選擇合適的GC Root ??捎米鱃C Root的對象主要有

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

引用分為三種類型

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

垃圾收集算法

標記清除

顧名思義,就是標記了再清除<br />缺點:效率低 會產生內存碎片

復制清除

為了解決效率問題,引出了復制算法。主要原理就是將內存分為兩塊,每次只使用一塊,當一塊用完了,就將還存活著的對象復制到另一塊內存中,然后將剩下的全部清除。<br />這個算法優(yōu)點就是 不會產生內存碎片,效率高,但是空間利用率不高(新生代用的就是復制算法,不同的是新生代將內存分為3塊 Eden,From Survivor ,To Survivor)比例默認是 8:1:1

標記整理

標記整理算法和標記清除類型,不同的是 清除之后,會進行內存整理,以減少內存碎片

分代收集

分代收集嚴格來說并不是一種收集算法,僅僅只是一種思想。它把內存分成各個區(qū)域,每個區(qū)域都使用合適的算法去做垃圾回收,如新生代使用復制算法,老年代使用標記整理<br /><br />

垃圾收集器

Serial 收集器

新生代單線程收集器(復制清除算法),收集的時候會 stop the world,一般都不怎么用了,除了在一些 Java桌面應用的CLient端還有用外

Parnew 收集器

新生代多線程收集器,serial 收集器的多線程版本,其他跟serial收集器完全一樣。清理的時候也會 stop the world。一般用來搭配使用 CMS 收集器

Parallel Scavenge 收集器

和 Parnew 收集器非常相似,都是新生代多線程收集器,但是Parallel Scavenge與其他收集器的關注點不一樣,它不關注 停頓時間點(stop the world),而關注吞吐量

Serial Old 收集器

serial 收集器的老年代版本,單線程收集器,使用標記整理算法,不怎么用。用來做CMS的后備

CMS

基于標記清除。CMS 是目前公司使用的 老年代收集器,也是大多數Web應用所采用的收集器。原因在于CMS收集器是以最短回收停頓時間為目前的收集器,對于用戶體驗來說會比較友好。<br />CMS 收集器包含四個步驟

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

缺點

  • 對CPU敏感
  • 無法處理浮動垃圾,重新標記的時候也會產生垃圾
  • 內存碎片 標記清除算法的通病

G1收集器

目前最屌的了

  • 停頓時間力求最短
  • 標記整理
  • 不需要配合其他收集器,一個就可以搞定 新生代 和老年代
  • 可預測的停頓 (??這是)

回收策略

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

  • 大對象直接進入老年代
  • 長期存活對象進入老年代 (默認是15次 -XX:MaxTenuingThrehold = 15 設置)
  • 空間分配擔保
    • 在發(fā)生MinorGC前,虛擬機會檢查老年代最大用連續(xù)空間是否大于新生代所有對象總空間,如果這個條件成立,則可以確保這次MinorGC是安全的。如果不成立虛擬機則會檢查 HandelPromotionFailure 設置值是否允許擔保失敗。如果允許則繼續(xù)檢查老年代最大可用空間是否大于歷次新生代晉升到老年代對象的平均大小,如果大于,則盡管有風險也會進行一次MinorGC。如果小于或則不允許擔保失敗,則直接進行 Full GC

<br />

虛擬機監(jiān)測工具

jps

  • jps -v 輸出啟動詳細信息
  • jps -l 輸出主類全名
  • jps -m 輸出main函數
  • jps -q 輸出 進程id

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

jstat

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

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

jinfo

查詢配置信息

jmap

生成內存快照

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

jhat

分析 dump文件的工具,不過有點難用

jstack

打印線程堆棧

  • jstack vmid

一般分析堆棧異常時用到,常用的命令組合是

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

這個比較好用,也很強大

有些時候,這些工具真的用不到。但并不代表,你不需要去了解這些

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容