淺入理解JVM虛擬機器

2022-09-18 07:09:21 字數 3329 閱讀 4328

1. 類載入過程

驗證 —— 準備 —— 解析 —— 初始化

驗證階段: 判斷.class檔案符合規範標準

準備階段:給類以及靜態變數分配記憶體並給初始值 「0」

解析階段: 維護哥哥字段,方法類的記憶體指標或偏移量

初始化階段:  變數賦值(真實的值),執行**

什麼時候乙個類會進行初始化階段?

1.new乙個例項化物件時

2.包含main方法的主類

3.需要初始化子類時,必須先初始化父類

2. tomcat如何實現熱部署?

類載入器與雙親委派機制

啟動類載入器 —— 擴充套件類載入器 —— 應用類載入器 —— 自定義類載入器

雙親委派機制也就是拿到乙個類,先交給他的父類載入器載入,一層一層傳遞,如果都載入不了再回到自己的載入器載入,

這樣就保證了每個類都會盡可能的在最上層載入器載入,且只會載入一次。保證了沙箱安全

tomcat的實現方式

第二種,jsp類檔案使用jsp類載入器載入,jsp類載入器屬於一次性的

當jsp檔案每次被修改時,都會使用乙個新的jsp類載入器載入。每此都會有新的jsp載入到jvm,並丟棄上乙個

3. 垃圾**器與垃圾**演算法

1.複製演算法,用於新生代,eden區與s1區中存活物件複製到s2區,剩下物件乾掉

優點:不會產生記憶體碎片  缺點: 始終浪費一塊空間

2.標記清除演算法,用於老年代,先標記出哪些是垃圾,再統一清理

優點:節省空間     缺點:容易產生記憶體碎片

3.標記整理演算法,用於老年代,就是在標記清除的基礎上加一次整理,把記憶體碎片乾掉

缺點:耗時

parnew垃圾**器,用於新生代,支援多執行緒,stw

cms垃圾**器,用於老年代,四個階段 初始標記(標記gcroot直接引用物件) —— 併發標記(gcroot間接引用物件) —— 再次標記(補充併發標記中建立的物件) —— 併發清除 

(gcroot直接引用物件包括靜態變數,區域性變數所引用的物件。 間接引用物件指的是,其中被引用的物件的全域性變數物件這種) 

其中初始標記和再次標記是stw的,也占用的時間比較短

cms採用標記清除,可配置jvm引數,多少次標記清除後一次標記整理

4. 關於gcroot

用作可達性分析的根,一般是類靜態變數和棧中的區域性變數的物件

finalize()方法,

gc前會呼叫該物件的finallize()方法,試圖搶救一下。所以可以在該方法中將當前物件掛上gcroot鏈路,避免被**

finalize 方法只會被執行一次,如果第一次執行 finalize 方法此物件變成了可達確實不會**,但如果物件再次被 gc,則會忽略 finalize 方法,物件會被**!

5. 關於方法區

方法區屬於概念,jdk1.8之前是永久代實現(與堆記憶體連續的),之後是元空間實現(在jvm外的本地記憶體)

方法區存的是類的模板,動態生成的類,靜態變數,常量池(注意1.8以後常量池物理上存在於堆記憶體,但是邏輯上還是屬於方法區的,咱也不懂)

方法區發生**需要滿足的條件

1.該類的所有例項物件都已經被jvm**

2.載入該類的類載入器被**

3.該類的class物件沒有任何引用

(個人感覺這些條件如此苛刻,因此方法區溢位導致的fullgc大概率不起什麼作用,方法區**不掉,從而導致無限的fullgc)

6. 物件進入老年代的幾種情況

1.在年輕代反覆存活15次,正常進入老年代 (在預設jvm引數配置下)

2.大物件從建立直接進入到老年代

3.一次younggc後存活的物件太多導致s2區裝不下,會有部分物件直接進入老年代而不是全部物件

4.動態年齡判斷規則,younggc後 年齡1 + 年齡2 + 年齡3 + ... 年齡n的物件總和大於s區的50%,則年齡最大的物件進入到老年代

7. 觸發oldgc的幾種情況

1.最正常情況,老年代空間不足,占用超過92%,直接觸發oldgc

2.在younggc後,晉公升到老年代的物件大於老年代剩餘空間,觸發oldgc

3.老年代空間擔保機制,

在younggc之前,先判斷老年代剩餘空間是否小於平均每次younggc的大小。 先觸發一次oldgc 再進行younggc

8. 出現oom的幾種情況

堆記憶體溢位:

1.高併發,請求量大,或者計算複雜,導致大量物件存活且gc幹不掉

2.系統記憶體漏洞,導致大量物件記憶體洩漏(如經典八股文threadlocal)

方法區溢位:

1.給metespace的空間太小了 (一般不會出現,除非人為的設定太小)

2.cglib等動態生成的類太多造成溢位

棧空間溢位:

1.一般是**問題,無限遞迴,導致不斷地方法棧入棧

9. gc調優的思路

一句話:盡量讓物件在新生代分配和**而不進入老年代,也就減少fullgc的影響

第一類,少讓物件進入老年代

1.少用大物件

2.適當提高晉公升年齡閾值

3.適當提高年輕代大小及s區大小

4.盡量讓物件快點死,朝生夕死,不要拖著不死導致幹不掉,最後拖到老年代了

第二類,減少younggc次數

1.少建立無用物件

第三類,減少fullgc次數

1. 少讓物件進入老年代,也就少觸發fullgc (好像廢話)

2. 適當調大老年代的空間

3.避免動態建立太多類導致方法區打滿,從而導致fullgc

4.避免幹不掉的物件,如記憶體洩漏導致頻繁fullgc

5.fullgc後適當進行標記整理,減少記憶體碎片

10. gc調優工具

gc日誌

1.younggc日誌

2.fullgc日誌

jstat

1. 檢視jvm eden,surivor區以及老年代記憶體的使用情況

2. 檢視younggc,fullgc的執行次數和耗時,觸發頻率

3.檢視新生代物件增長速率,老年代物件增長速率

jmap

1.檢視eden區,surivor區,以及老年代記憶體使用佔比

2.檢視記憶體中物件占用情況,具體到哪個包下的哪個類,佔了多大

3.dump下此時的記憶體快照,利用分析工具分析

jvm調優案例分析

深入理解JVM虛擬機器 鎖優化

jvm中使用到的鎖優化技術主要包括 自旋鎖和適應性自旋鎖 鎖消除 鎖粗化 輕量級鎖 偏向鎖 1.自旋鎖和自適應鎖 當乙個執行緒執行耗時小的一小段同步 另乙個執行緒可以不放棄處理器的執行時間,等待看看持有鎖的執行緒是否很快就會釋放鎖,為了使執行緒等待,可以讓執行緒執行忙迴圈 自旋 自適應自旋是指自旋的...

深入理解Java虛擬機器 JVM記憶體洩漏

jvm記憶體洩漏 記憶體洩漏就是存在一些物件沒有被 這些物件是可達的,但是這些物件是無用的,那麼這些物件就存在記憶體洩漏,即不會被gc 但是卻占用記憶體。記憶體溢位主要分為以下幾種 1.靜態集合類引起記憶體洩漏 像hashmap vector等的使用最容易出現記憶體洩露,這些靜態變數的生命週期和應用...

jvm虛擬機器

jvm虛擬機器 執行時資料 虛擬機器棧中每個執行緒單獨占有 xss引數大小的記憶體.乙個執行緒使用記憶體超出此引數則丟擲stackoverflowerror,比較常見的就是死迴圈.oom是在申請不到記憶體時,常見的就是建立很多執行緒.堆中記憶體所有執行緒共享.分為年輕代和老年代.年輕代gc一些大物件...