jvm中的物件和GC
物件的建立:
給物件分配記憶體的方式
指標碰撞(GC策略如具有壓縮整理的功能,能夠將堆記憶體劃分為已使用和空閒的記憶體的時候可以使用指標碰撞,否則的話使用空閒列表)
空閒列表()
給物件分配記憶體執行緒安全性問題
執行緒同步加鎖(效能很低)
本地執行緒分配緩衝(每一個執行緒分配一個緩衝記憶體,這樣的話,就不會存在同步訪問同一個資源的問題)
初始化物件
物件的結構:
-
- header(物件頭)
- 自身執行時資料
- 雜湊值 GC分帶年齡 鎖狀態標誌 執行緒持有的鎖 偏向執行緒ID 偏向時間戳 等
- 這部分資料的長度在32位和64位的虛擬機器(暫 不考慮開啟壓縮指標的場景)中分別為32個和64個Bits,官方稱它為“Mark Word”。
- 自身執行時資料
- header(物件頭)
-
-
- 型別指標(物件指向它的類的元資料的指標,虛擬機器通過這個指標來確定這個物件是哪個類的例項,但是並不是所有的虛擬機器都會保留型別指標)
- 如果物件是一個Java陣列,那在物件頭中還必須有一塊用於記錄陣列長度的資料
- InstanceDate(資料的例項,儲存物件的有效資訊)
- Hotspot的分配策略是相同寬度的欄位會分配在一塊
- Padding(對齊填充,填充資料,不一定存在)
- 相當於佔位符(因為Hotspot要求物件的起始地址必須是8個位元組的整數倍,所以如果物件的例項資料如果不是8個位元組,則使用padding填充)
-
執行構造方法
物件訪問定位:
使用控制代碼
直接指標(hotspot使用的是直接指標)
垃圾回收GC
如何判斷物件為垃圾物件
- 引用計數法
在物件中(堆記憶體中)新增一個引用計數器,當有地方引用這個物件的時候,引用計數 器的值就+1,當引用失效的時候,計數器的值就-1
可在Java的Run Configurations中設定如下引數,即可在進行垃圾回收的時候就可以在控制檯看見垃圾回收的日誌資訊
-verbose:gc
-xx:+PrintGCDetails
- 可達性分析法(目前的主流的垃圾回收器都使用該方法)
定義一個垃圾回收的跟節點(GCRoot),從這個root節點開始找,當一個物件對root節點沒有任何的引用鏈(找的時候走過的鏈路)相連線的時候,就判斷這個物件是垃圾物件
能夠作為GCRoots的物件
- 虛擬機器棧(棧幀中區域性變量表)
- 方法區的類屬性所引用的物件
- 方法區總常量所引用的物件
- 本地方法棧中所引用的物件
如何回收
- 回收策略
- 標記-清除演算法
- 效率問題
- 空間問題(會產生許多不聯絡的記憶體空間)
- 複製演算法
- 標記-清除演算法
為了方便垃圾回收,將堆記憶體分割槽
-
-
- 新生代
- Eden 伊甸園
- survivor 存活期
- tenured Gen 老年代
- 老年代
- 新生代
- 標記-整理-清楚演算法
- 主要針對老年代的垃圾回收(垃圾很少,可用物件很多)
- 分代收集演算法
- 新生代使用複製演算法
- 老年代使用標記-整理-清楚演算法
-
- 垃圾回收器
- Serial (複製演算法)
- 單執行緒垃圾收集器(其他執行緒會暫停)
- 適合桌面運用
- 歷史比較悠久
- Parnew(複製演算法)
- 多執行緒垃圾收集器(其他執行緒需要暫停)
- 新生代收集器
- parallel scavenger (複製演算法)
- 多執行緒垃圾收集器(其他執行緒需要暫停)
- 新生代收集器
- 達到可控制的吞吐量(吞吐量=執行使用者程式碼的時間/(執行使用者程式碼的時間+垃圾回 收所佔用的時間))
- -xx:MaxGCPauseMillis垃圾收集器最大停頓時間
- -xx:GCTimeRatio 吞吐量大小
- 範圍(0,99)
- Cms (Conturrent Mark Sweep)
- 使用標記-清除演算法實現
- 減少延遲,提高響應速度
- 工作流程
- 初始標記
- 併發標記
- 重新標記
- 併發清理
- 優點
- 併發收集
- 低停頓
- 缺點
- 佔用大量的CPU資源
- 無法處理浮動垃圾
- 出現concurrent mode failure
- 記憶體空間碎片
- G1收集器(jdk1.9)
- 優勢
- 並行與併發
- 分代收集
- 空間整合(標記-整理演算法的優勢)
- 可預測的停頓
- 工作流程
- 初始標記
- 併發標記
- 最終標記
- 篩選回收(remember set表)
- 優勢
- Serial (複製演算法)
何時回收
物件記憶體的分配
記憶體分配策略
- 優先分配到Eden
- 大物件直接分配到老年代
- 長期存活的物件分配到老年代
- 空間分配擔保
- 動態物件年齡判斷
物件優先在Eden上分配
-Xms256m -Xmx1024m 堆記憶體的初始大小和最大大小
-XX:PermSize是初始永久儲存區域大小,-XX:MaxPermSize是最大永久儲存區域大小
大物件直接進入老年代
-XX:PretenureSizeThreshold=3145728
引數設定超過物件超過多少時,直接分配到老年代中
長期存活物件將進入老年代
年齡計數器:age1+1+1(存活一次age+1,當達到15(預設)之後,就會直接進入老年代)
-XX:MaxTenuringThreshold=15(預設15,不一定是15次之後才會進入老年代)
空間分配擔保
當新生代空間不夠的時候,會向老年代借用
-XX:+HandlePromotionFailure +號是開啟,預設是開啟的,-號是關閉
逃逸分析與棧上分配
逃逸分析:分析物件的作用域。
如果一個物件的作用域只是在方法之中(例如區域性變數),那麼給該物件的記憶體分配到棧中,隨著方法的出棧而釋放記憶體。