第三章JVM

3.1 JVM 基礎 3.2 JVM 內存佈局及三色標記算法 3.3 JVM 調優

3.1 JVM 基礎

基礎主要簡單過一下,不瞭解的百度搜很多
Java理解

平臺無關性-- javac編譯 javap反彙編,一次編譯到處運行
GC垃圾回收
語言特性--泛型,反射等
面向對象--封裝,繼承,多態
類庫--Java本身集合,IO等
異常處理

異常處理
Throwable -> error 和 exception
exception -> runtimeException 和 非runtimeException
error 是JVM負責
runtimeException 是程序負責
checkedException 也就是非runtime是 Java編譯器負責

類加載過程

作者:柯西王子
鏈接:https://www.nowcoder.com/discuss/401895?type=2
來源:牛客網
類加載器的本質其實就是通過文件操作掃描到應用classpath下的Jar包,然後讀取
Jar包裏的class文件,經過解析,校驗等等一堆亂七八糟的操作之後,再將文件裏
的字節碼內容加載到內存裏,供後面類實例化爲對象使用,實例化對象的時候會根
據已加載的類信息去做分配內存,初始化成員變量等等一些工作

JVM架構(稍微看看即可)
ClassLoader 根據特定格式,加載class文件到內存
Runtime Data Area 是JVM內存空間模型
Execution Engine 解析命令到操作系統
Native Interface 不同語言的原生庫爲Java使用

反射
簡單略

雙親委派機制

BootStrapClassLoader C++編寫加載核心庫
ExtClassLoader: Java編寫,加載擴展庫
AppClassLoader:Java編寫,加載程序所在目錄
自定義ClassLoader:Java編寫,定製化加載

定義流程--略
Why use--避免重複加載
How 自定義? extend ClassLoader 
-> 重寫findClass 不打破雙親
-> 重寫loadClass 打破雙親

Java內存模型

線程私有的--程序計數器,虛擬機棧,本地方法棧
線程共有的--MetaSpace,堆(常量池和堆)

各自定義,元空間方法區,Intern JDK6改動等等太基礎略

GC

引用計數法
可作爲GC root對象:虛擬機棧,方法區,活躍線程,本地方法棧中各種對象等
標記清除算法
標記整理算法
複製算法
年輕代
老年代
觸發full GC條件
常用垃圾收集器
stop-the-world
safepoint
強引用,軟引用,弱引用,虛引用,引用隊列
CMS 初始標記,併發標記,重新標記,併發清除及原理(性能不咋地,一直被嫌棄)
G1 堆內存劃分,維護優先級,會清除垃圾最多的
太基礎略

JMM內存模型
happen-before原則等等,蠻重要的略

3.2 JVM 內存佈局及三色標記算法

對象在內存中佈局

普通對象

對象頭(8字節)
類型指針(4字節)
實例數據(根據具體數據判斷,一個int4字節,一個long8字節推類)
對齊 (當整個字節不能被8整除時,則填衝到被8整除)

數組對象

對象頭(8字節)
類型指針(4字節)
數組長度
對齊 (當整個字節不能被8整除時,則填衝到被8整除)

一般Java 類型指針64位,但是JVM默認開啓compressedPointer會壓縮到4字節。compressedOops也會壓縮普通對象字節,如String默認是8字節,但是String會被壓縮到4字節

例題
User{
int id;
String name;

整個類佔多少字節?

對象頭8字節,類型指針4字節,int4字節,string4字節,對齊4字節(因爲前面只有20字節不能被8整除,自動填充4字節)。總共24字節

垃圾回收算法
CMS 三色標記算法-標錯+寫屏障
G1 三色標記算-STAB+寫屏障
ZGC 顏色指針,着色指針+讀屏障

三色標記算法
對象分三種類型:黑色,灰色,白色

黑色指確認不是垃圾並且成員變量已找完
灰色指確認不是垃圾,但是還沒有識別成員變量
白色指還沒有確認自己是不是垃圾,會被當成垃圾回收

遍歷所有灰色對象,把灰色對象下白色成員變量都變成灰色後自己變成黑色。
依次反覆知道遍歷完整個灰色對象。然後垃圾回收所有白色對象,因爲這寫白色
對象不可達

情況分析

黑色對象A—(引用)—> 灰色對象B --(引用)—> 白色對象C

場景1

灰色對象和白色對象中間引用消失
這種情況不會產生問題,白色對象本身就是浮動垃圾,
不可達,就應該被清除

場景2

灰色對象和白色對象中間引用消失,但是黑色對象和白色對象中間增加引用
這種情況會產生問題,黑色對象因爲已經標記查完成員變量,所以不會再查
這個白色對象,白色對象將會被當成垃圾回收。但是白色對象C現在已經和
黑色對象A產生引用,可達了,不應該是垃圾,產生了矛盾

對於場景2的問題

CMS解決方案:寫入屏障方法,A,C新增引用時候,通過寫屏障算法把C白色對象
強行變成灰色,這樣下一次就可以繼續遍歷灰色對象C了,C不會被垃圾回收

那麼CMS爲什麼需要重新標記呢?

併發標記階段加入的新白色對象不能直接GC回收,所以需要重新標記上述步驟

最後就是併發清除—標記清除算法,會產生嚴重碎片化

CMS 垃圾回收器可以和用戶線程一起併發執行,如果這時候用戶線程內存空間不夠怎麼辦?

這個時候會報錯,可以用Serial Old 垃圾回收器
替代 CMS 進行 stop the world 垃圾回收

3.3 JVM 調優

調優步驟

1 熟悉業務場景:啓動慢,響應慢,吞吐量低等等
2 目標:內存佔用,低延遲,吞吐量大
3 收集日誌:通過參數收據GC日誌,通過JDK工具實時查看GC狀態
4 分析日誌:可以通過Arthas輔助分析日誌
5 調整參數:切換垃圾收集器,調參數等等

場景1 (定位處理OOM)

1 jps 查找進程id號(如id號1011)
2 jmap -histo 1011 | head 20 查看哪些類產生多少個對象
(少用jmap,因爲jmap時候會影響線上性能)
3 發現線程池實例不停增加,問題找到
4 可以用redefine線上內存中直接修改代碼,不停服務器,問題解決

場景2(性能調優)

1 java -Xmax 1024 m -X loggc: xxxx -jar xxxxx
比如測試環境下,配置參數啓動項目並打印日誌
2 jstat -gc id xxxx
查看gc次數和gc時間(PerallelGCThreads默認2個線程)
3 配置PerallelGCThreads4個線程重新運行,再jstat比較發現gc時間變大了,
這方法不行
4 改CMS再重新運行,再jstat比較發現gc時間依然變大不可取
5 改G1,發現仍然不咋地
6 。。。。。不停改看哪個性能好用哪個
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章