### 類的生命周期

JVM類加載過程可劃分為三個過程:裝載、鏈接和初始化
初始化過程不是加載類時必須觸發的,但最遲必須在初次主動使用對象前執行,其所作的動作為給靜態變量賦值、調用<clinit>\(\)等;
JVM通過類的全限定名+ClassLoader實例ID唯一標識一個被加載的類
##### 加載
加載階段主要完成三件事,即通過一個類的全限定名來獲取定義此類的二進制字節流,將這個字節流所代表的靜態存儲結構轉化為方法區的運行時數據結構,在Java堆中生成一個代表此類的Class對象,作為訪問方法區這些數據的入口。這個加載過程主要就是靠類加載器實現的,這個過程可以由用戶自定義類的加載過程
##### 驗證
這個階段目的在于確保class文件字節流中包含的信息符合當前虛擬機要求,不會危害虛擬機自身安全。
主要包括四種驗證:
1. 文件格式驗證:基于字節流驗證,驗證字節流是否符合Class文件格式的規范,并且能被當前虛擬機處理;
2. 元數據驗證:基于方法區的存儲結構驗證,對字節碼描述信息進行語義驗證;
3. 字節碼驗證:基于方法區的存儲結構驗證,進行數據流和控制流的驗證;
4. 符號引用驗證:基于方法區的存儲結構驗證,發生在解析中,是否可以將符號引用成功解析為直接引用
##### 準備
僅僅為類變量(即static修飾的字段變量)分配內存并且設置該類變量的初始值即零值,這里不包含用final修飾的static,因為final在編譯的時候就會分配了(編譯器的優化),同時這里也不會為實例變量分配初始化。類變量會分配在方法區中,而實例變量是會隨著對象一起分配到Java堆中
##### 解析
解析主要就是將常量池中的符號引用替換為直接引用的過程。符號引用就是一組符號來描述目標,可以是任何字面量,而直接引用就是直接指向目標的指針、相對偏移量或一個間接定位到目標的句柄。有類或接口的解析,字段解析,類方法解析,接口方法解析
##### 初始化
初始化階段依舊是初始化類變量和其他資源,這里將執行用戶的static字段和靜態語句塊的賦值操作。這個過程就是執行類構造器< clinit >方法的過程。
< clinit >方法是由編譯器收集類中所有類變量的賦值動作和靜態語句塊的語句生成的,類構造器< clinit >方法與實例構造器< init >方法不同,這里面不用顯示的調用父類的< clinit >方法,父類的< clinit >方法會自動先執行于子類的< clinit >方法。即父類定義的靜態語句塊和靜態字段都要優先子類的變量賦值操作
### 基本的加載流程
尋找jre目錄,尋找jvm.dll,并初始化JVM;
產生一個Bootstrap Loader(啟動類加載器);
Bootstrap Loader,該加載器會加載它指定路徑下的Java核心API,并且再自動加載Extended Loader(標準擴展類加載器),Extended Loader會加載指定路徑下的擴展JavaAPI,并將其父Loader設為BootstrapLoader。
Bootstrap Loader也會同時自動加載AppClass Loader(系統類加載器),并將其父Loader設為ExtendedLoader。
最后由AppClass Loader加載CLASSPATH目錄下定義的類,HelloWorld類。
創建自己的類加載器
在Java應用開發過程中,可能會需要創建應用自己的類加載器。典型的場景包括實現特定的Java字節代碼查找方式、對字節代碼進行加密/解密以及實現同名Java類的隔離等。創建自己的類加載器并不是一件復雜的事情,只需要繼承自java.lang.ClassLoader類并覆寫對應的方法即可
【參考資料】
[https://blog.csdn.net/CSDN\_980979768/article/details/47281037](https://blog.csdn.net/CSDN_980979768/article/details/47281037)
- 前言
- Write once, run anywhere
- 概述
- JAVA虛擬機
- JVM整體結構
- JVM架構模型
- JVM虛擬機分類
- HotSpot VM
- JRockit
- IBM-J9
- Azul/zing VM
- Taobao VM
- Dalvik VM
- Graal VM
- JAVA源碼編譯機制
- Javac編譯器
- 分析和輸入到符號表
- 注解處理
- 語義分析和生成class文件
- ECJ編譯器
- 類執行機制
- 字節碼解釋執行
- 棧頂緩存
- 部分棧幀共享
- 編譯執行
- 即時編譯器
- C1 Compiler
- C2 Compiler
- Graal編譯器
- C1與C2編譯器
- AOT
- 編譯優化
- 字符串優化
- 方法內聯
- 逃逸分析
- 同步消除
- 標量替換
- 棧上分配
- 去虛擬化/逆優化
- 多層編譯
- JVM編譯策略
- OSR編譯
- 冗余削除
- CodeCache
- 常量編譯優化
- JVM運行時數據區
- 程序計數器
- JAVA虛擬機棧
- 棧幀
- 局部變量表
- 操作數棧
- 本地方法棧
- Java調用native方法
- JVM Stacks && Native Stacks
- 堆-Heap
- 方法區(Method Area)
- 運行時常量池
- 常量傳播優化
- MetaSpace
- 直接內存
- StackOverflowError
- 遞歸方法
- OutOfMemoryError
- 本地內存溢出
- 執行引擎
- 運行時數據區關聯關系
- jdk8內存結構
- JMM內存模型
- JAVA內存模型
- JMM八種操作指令
- 內存屏障
- 指令重排
- as-if-serial語義
- Happen-Before規則
- 數據依賴性
- 原子性、可見性與有序性
- 偽共享
- CPU三級緩存
- 緩存行
- MESI協議
- Java中的偽共享
- ConcurrentHashMap偽共享解決方案
- 虛擬機對象
- 對象創建原理
- 對象內存布局
- 對象頭
- 實例數據
- 對象的訪問定位
- 垃圾收集器與內存分配策略
- GC相關概念
- TLAB
- JVM GC工作原理
- 內存管理
- JAVA引用分類
- 死亡標記
- 回收方法區
- 三色標記算法
- 垃圾收集算法
- 標記-清除算法
- 標記-整理算法
- 復制算法
- 分代收集算法
- HotSpot算法實現
- STW
- 垃圾收集器
- 常見的垃圾收集器
- 垃圾收集器分類
- Serial收集器
- Serial Old收集器
- ParNew收集器
- Parallel Scavenge收集器
- Parallel Old收集器
- CMS收集器
- CMS完整收集過程
- Card Table
- G1收集器
- 分代收集
- 空間整合
- 可預測的停頓時間模型
- G1&CMS
- 主要參數說明
- G1適用場景
- Remembered Set
- G1垃圾回收的過程
- G1優化建議
- Shenandoah
- ZGC
- 垃圾收集器特點
- GC日志
- GC策略的評價指標
- jvm card table數據結構
- 對象生存軌跡
- 類文件結構
- 魔數
- 版本號
- 常量池
- 訪問標志
- 父類索引
- 接口集合
- 字段集合
- 方法集合
- 屬性集合
- 類加載機制與類的初始化
- Java代碼執行流程
- 類加載過程
- 抽象類ClassLoader
- 常見類加載器
- BootstrapClassLoader
- 自定義類加載器
- 線程上下文類加載器
- 雙親委派模型
- Tomcat類加載機制
- ServiceLoader
- 類的初始化
- 常見的JVM類加載異常
- ClassNotFoundException
- NoClassDefFoundError
- LinkageError
- ClassCastException
- 虛擬機性能調優監控與故障處理工具
- CPU利用率高/飆升
- 排查及解決方案
- 上下文切換
- GC問題定位解決方案
- prommotion failed
- FullGC頻繁
- youngGC
- 內存問題
- 內存溢出和內存泄漏
- 內存溢出
- 棧溢出
- 堆溢出
- 對外內存溢出
- 內存泄漏
- 磁盤問題
- 線上問題解決方案
- 不定期出現的接口耗時現象
- 線程池異常
- 死鎖問題
- JVM調優
- jvm參考配置
- jvm-jstat
- jvm-jmap
- jvm-jstack
- jinfo
- jps
- 虛擬機的退出
- Shutdown Hook
- JVM指令
- 附錄
- 常用JVM指令
- Class文件版本號
- Class文件格式
- 方法訪問標識
- jvm常量池
- 類或接口的訪問標識
- 描述符標識字符含義
- 字段訪問標識
- Java程序與Docker容器環境
- 基準測試