我是
方圓
,一邊做課程設計,一邊更博客
目錄
1. native關鍵字(瞭解)
Java無法直接訪問系統的底層
(我們熟悉的啓動線程中start0()方法就是被native關鍵字修飾),所以,引入native關鍵字對Java實現擴展,通過JNI(Java Native Interface)
接口調用其他語言(如C和C++),實現對底層的訪問。
2. 方法區
方法區中存在靜態變量
,常量
,類信息
,運行時常量池
存在方法區中,但是實例變量存在堆內存中,和方法區無關。(static,final,Class,常量池)
3. 棧
棧中保存的是八大基本類型,對象的引用
4. 類的加載過程
類的生命週期如下圖所示
加載
在加載階段,我們可以參考java.lang.ClassLoader中的loadClass()方法,會在方法區
中生成一個代表這個類的java.lang.Class對象,作爲方法區這個類的各種數據的訪問入口驗證
這個階段主要確保了Class文件的字節流中包含的信息符合虛擬機的要求,並且不會危害虛擬機的安全。驗證是非常重要的,但是不是必須的,它對程序運行期沒有影響
準備
準備階段是正式爲類變量(static)
分配內存並設置初始值的階段,這些變量所使用的內存都在方法區
中分配。解析
解析階段是虛擬機將常量池內的符號引用替換爲直接引用的過程。初始化
這個階段是類加載過程的最後一步。在準備階段,我們已經對類變量賦值過(初始0值),而在這個初始化階段,則根據我們寫的代碼去初始化變量和其他資源。或者說,初始化階段是執行類構造器<clinit>()
方法的過程。<clinit>()方法
是由編譯器自動收集類中所有的類變量賦值語句
和靜態代碼塊中的賦值語句
所產生的。
虛擬機會保證一個類的類構造器<clinit>()
在多線程環境中被正確的加鎖、同步
,如果多個線程同時
去初始化一個類,那麼只會有一個線程
去執行這個類的類構造器<clinit>()
,其他線程都需要阻塞等待,直到活動線程執行<clinit>()
方法完畢。需要特別注意的是,其他線程雖然會被阻塞,但是當<clinit>()
執行完畢,其他線程被喚醒之後不會再去執行這個方法,因爲在同一個類加載器下,一個類型只會被初始化一次
。
5. 對象的實例化過程
實例化一個類的對象,是一個典型的遞歸過程,如下圖所示。
在準備實例化一個對象前,首先會準備實例化該類的父類,如果該類的父類還有父類,那麼還會向上實例化,直到遞歸到Object類。實例化Object類之後,再依次向下對各類進行實例化。
5.1 舉一個小例子
Student student = new Student();
- 當虛擬機遇到一條new命令的時候,先檢查方法區中
是否存在該對象的類信息
,並且檢查該類是否被加載、解析和初始化
(1)如果方法區中沒有該類的信息,那麼會拋處ClassNotFoundException
(2)若以上的檢查全部通過,則進入下一步工作 - 類加載完成後,虛擬機將爲新生對象分配內存
- 從堆中劃分一塊兒相應大小的內存給新的對象
- 爲新對象的成員變量附上初始值
- 設置並保存對象頭信息(Object Header),對象頭信息包括該對象是哪個類實例、對象的哈希碼、對象的 GC 分代年齡等信息
- 一般來說,執行 new 指令之後會接着執行 方法,把對象按照程序員規定的構造函數進行初始化
6. 堆
堆
中存放的是對象,包含年輕代和老年代,永久代
(在jdk1.8被元空間取代)中包含方法區
6.1 分代概念
新生成的對象首先放到年輕代Eden區,當Eden空間滿了
,觸發Minor GC,存活下來的對象移動到Survivor0區,Eden再次填滿後
觸發執行Minor GC,Survivor0區存活對象移動到Suvivor1區,這樣保證了一段時間內總有一個survivor區爲空(空的爲to,非空的爲from)。經過15
次Minor GC仍然存活的對象移動到老年代。
老年代
存儲長期存活的對象,佔滿時
會觸發Major GC=Full GC,GC期間會停止所有線程等待GC完成,所以對響應要求高的應用盡量減少發生Major GC,避免響應超時。
Minor GC
: 清理年輕代Major GC
: 清理老年代Full GC
: 清理整個堆空間,包括年輕代和永久代
6.2 爲什麼分代?
將對象根據存活概率進行分類,對存活時間長的對象,放到固定區,從而減少掃描垃圾時間及GC頻率。針對分類進行不同的垃圾回收算法,對算法揚長避短。
6.3 爲什麼survivor分爲兩塊相等大小的倖存空間?
主要爲了解決碎片化。如果內存碎片化嚴重,也就是兩個對象佔用不連續的內存,已有的連續內存不夠新對象存放,就會觸發GC。
6.4 JVM堆內存中常用參數
參數 | 描述 |
---|---|
-Xms | 堆內存初始化大小 |
-Xmx | 堆內存最大允許大小,一般不超過物理內存的80% |
-XX:+PrintGCDetail | 打印GC詳細信息 |
-XX:PermSize | 非堆內存初始大小,一般設置200M |
-XX:MaxPermSize | 非堆內存允許的最大大小 |
-Xns | 年輕代內存初始化大小 |
-Xmn | 年輕代內存允許的最大內存大小 |
-XX:SurvivorRatio=8 | Eden區與Survivor區的容量比值,默認爲8 |
-Xss | 棧內存大小 |