成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

逐夢offer -- JVM篇

greatwhole / 2897人閱讀

摘要:的字節(jié)碼解釋器和編譯器使用寫屏障維護(hù)卡表。解釋器每次執(zhí)行更新引用的字節(jié)碼時(shí),都會(huì)執(zhí)行一段寫屏障,編譯器在生成更新引用的代碼后,也會(huì)生成一段寫屏障。

4. JVM 4.1 GC 1. 垃圾收集

基礎(chǔ) : 可達(dá)性分析算法 GC ROOTS

復(fù)制算法

標(biāo)記清除

標(biāo)記整理

分代收集 -- 1. 新生代 ; 2.3 老年代
注: Oop Map -- 安全點(diǎn) -- 安全區(qū)

以下部分內(nèi)容 來自 這個(gè)博主的文章

1. 3種基本算法

標(biāo)記清除法/標(biāo)記壓縮法、復(fù)制收集算法、引用計(jì)數(shù)法

這里的 引用計(jì)數(shù)法 因?yàn)闀兄v解少,所以講一下:
引用計(jì)數(shù)法,它的基本原理是,在每個(gè)對象中保存該對象的引用計(jì)數(shù),當(dāng)引用發(fā)生增減時(shí)對計(jì)數(shù)進(jìn)行更新。引用計(jì)數(shù)的增減,一般發(fā)生在變量賦值、對象內(nèi)容更新、函數(shù)結(jié)束(局部變量不再被引用)等時(shí)間點(diǎn)。當(dāng)一個(gè)對象的引用計(jì)數(shù)變?yōu)?時(shí),則說明它將來不會(huì)再被引用,因此可以釋放相應(yīng)的內(nèi)存空間。
缺點(diǎn):

無法釋放循環(huán)引用的對象。

必須在引用發(fā)生增減時(shí)對引用計(jì)數(shù)做出正確的增減,而如果漏掉了某個(gè)增減的話,就會(huì)引發(fā)很難找到原因的內(nèi)存錯(cuò)誤。引用數(shù)忘了增加的話,會(huì)對不恰當(dāng)?shù)膶ο筮M(jìn)行釋放;而引用數(shù)忘了減少的話,對象會(huì)一直殘留在內(nèi)存中,從而導(dǎo)致內(nèi)存泄漏。

引用計(jì)數(shù)管理并不適合并行處理: 就如同 ConcurrenHashMap源碼分析 中的算法一樣,無法在并行情況下對數(shù)量進(jìn)行準(zhǔn)確的計(jì)算。

2. 3種進(jìn)階算法

分代回收
分代回收的目的,正是為了在程序運(yùn)行期間,將GC所消耗的時(shí)間盡量縮短。

分代回收的基本思路,是利用了一般性程序所具備的性質(zhì),即大部分對象都會(huì)在短時(shí)間內(nèi)成為垃圾,而經(jīng)過一定時(shí)間依然存活的對象往往擁有較長的壽命。
HotSpot 虛擬機(jī)中,在新生代用復(fù)制算法,老年代使用標(biāo)記清除/整理算法。

問題:如果存在老生代對象對新生代對象的引用。如果只掃描新生代區(qū)域的話,那么從老生代對新生代的引用就不會(huì)被檢測到。
這樣一來,如果一個(gè)年輕的對象只有來自老生代對象的引用,就會(huì)被誤認(rèn)為已經(jīng)“死亡”了。
因此,在分代回收中,會(huì)對對象的更新進(jìn)行監(jiān)視,將從老生代對新生代的引用,
記錄在一個(gè)叫做記錄集 Rset(remembered set)的表中。在執(zhí)行小回收(Minor Gc)的過程中,這個(gè)記錄集也作為一個(gè)根來對待。

解決方案:在老生代到新生代的引用產(chǎn)生的瞬間,就必須對該引用進(jìn)行記錄,而負(fù)責(zé)執(zhí)行這個(gè)操作的子程序,需要被嵌入到所有涉及對象更新操作的地方。
這個(gè)負(fù)責(zé)記錄引用的子程序是這樣工作的。設(shè)有兩個(gè)對象:A和B,當(dāng)對A的內(nèi)容進(jìn)行改寫,并加入對B的引用時(shí),
如果①A屬于老生代對象,②B屬于新生代對象,則將該引用添加到記錄集中。
這種檢查程序需要對所有涉及修改對象內(nèi)容的地方進(jìn)行保護(hù),因此被稱為寫屏障(Write barrier)。

增量回收
為了維持程序的實(shí)時(shí)性,不等到GC全部完成,而是將GC操作細(xì)分成多個(gè)部分逐一執(zhí)行。這種方式被稱為增量回收

并行回收
并行回收的基本原理是,是在原有的程序運(yùn)行的同時(shí)進(jìn)行GC操作,這一點(diǎn)和增量回收是相似的。

不過,相對于在一個(gè)CPU上進(jìn)行GC任務(wù)分割的增量回收來說,并行回收可以利用多CPU的性能,盡可能讓這些GC任務(wù)并行(同時(shí))進(jìn)行。

3. Card Table 數(shù)據(jù)結(jié)構(gòu)

為了支持高頻率的新生代的回收,虛擬機(jī)使用一種叫做卡表(Card Table)的數(shù)據(jù)結(jié)構(gòu).
卡表作為一個(gè)比特位的集合,每一個(gè)比特位可以用來表示年老代的某一區(qū)域中的所有對象是否持有新生代對象的引用。

一、作用
卡表中每一個(gè)位表示年老代4K的空間,
卡表記錄為 0 的年老代區(qū)域沒有任何對象指向新生代,
卡表記錄為 1 的區(qū)域才有對象包含新生代引用,
因此在新生代GC時(shí),只需要掃描卡表位為1所在的年老代空間。使用這種方式,可以大大加快新生代的回收速度。

二、結(jié)構(gòu)
卡表是個(gè)單字節(jié)數(shù)組,每個(gè)數(shù)組元素對應(yīng)堆中的一張卡。
每次年老代對象中某個(gè)引用新生代的字段發(fā)生變化時(shí),Hotspot VM就必須將該卡所對應(yīng)的卡表元素設(shè)置為適當(dāng)?shù)闹?,從而將該引用字段所在的?strong>標(biāo)記為臟。
如下圖:

在Minor GC過程中,垃圾收集器只會(huì)在臟卡中掃描查找年老代-新生代引用。

Hotspot VM的字節(jié)碼解釋器和JIT編譯器使用寫屏障 維護(hù)卡表。
寫屏障 (Write barrier) 是一小段將卡狀態(tài)設(shè)置為臟的代碼。 解釋器每次執(zhí)行更新引用的字節(jié)碼時(shí),都會(huì)執(zhí)行一段寫屏障,JIT編譯器在生成更新引用的代碼后,也會(huì)生成一段寫屏障。
雖然寫屏障使得應(yīng)用線程增加了 -- 性能開銷,但Minor GC變快了許多,整體的垃圾收集效率也提高了許多,通常應(yīng)用的吞吐量也會(huì)有所改善。

4. 評價(jià)指標(biāo)

1、 吞吐量

應(yīng)用系統(tǒng)的生命周期內(nèi),應(yīng)用程序所花費(fèi)的時(shí)間和系統(tǒng)總運(yùn)行時(shí)間的比值
系統(tǒng)總運(yùn)行時(shí)間=應(yīng)用程序耗時(shí)+GC耗時(shí)
2、 垃圾回收器負(fù)載
垃圾回收器負(fù)載=GC耗時(shí)/系統(tǒng)總運(yùn)行時(shí)間
3、 停頓時(shí)間
垃圾回收器運(yùn)行時(shí),應(yīng)用程序的暫停時(shí)間
4、 垃圾回收頻率
垃圾回收器多長時(shí)間運(yùn)行一次。一般而言,頻率越低越好,通常增大堆空間可以有效降低垃圾回收發(fā)生的頻率,但是會(huì)增加回收時(shí)產(chǎn)生的停頓時(shí)間。
5、 反應(yīng)時(shí)間
當(dāng)一個(gè)對象成為垃圾后,多長時(shí)間內(nèi),它所占用的內(nèi)存空間會(huì)被釋放掉。

2. 內(nèi)存分配
1. 基礎(chǔ)知識(shí)

-Xms 堆大小
-Xmx 可擴(kuò)展大小
-Xmn 老年代大小
-XX:SurvivorRatio Eden 區(qū)與 Survivor 區(qū)大小比例
注: surivor 區(qū)分為 from 區(qū)與 to 區(qū)

- 在GC開始的時(shí)候,對象只會(huì)存在于Eden區(qū)和名為“From”的Survivor區(qū),Survivor區(qū)“To”是空的。
- 緊接著進(jìn)行GC,Eden區(qū)中所有存活的對象都會(huì)被復(fù)制到“To”,而在“From”區(qū)中,仍存活的對象會(huì)根據(jù)他們的年齡值來決定去向。
- 年齡達(dá)到一定值(年齡閾值,可以通過-XX:MaxTenuringThreshold來設(shè)置)的對象會(huì)被移動(dòng)到年老代中,沒有達(dá)到閾值的對象會(huì)被復(fù)制到“To”區(qū)域
- 經(jīng)過這次GC后,Eden區(qū)和From區(qū)已經(jīng)被清空。這個(gè)時(shí)候,“From”和“To”會(huì)交換他們的角色,也就是新的“To”就是上次GC前的“From”
- 新的“From”就是上次GC前的“To”。
- 不管怎樣,都會(huì)保證名為To的Survivor區(qū)域是空的。Minor GC會(huì)一直重復(fù)這樣的過程,直到“To”區(qū)被填滿,“To”區(qū)被填滿之后,會(huì)將所有對象移動(dòng)到年老代中。

大對象直接進(jìn)入老年代 :很長的字符串以及數(shù)組

長期存活的對象進(jìn)入老年代 -XX:MaxTenuringThreshold

動(dòng)態(tài)對象年齡判定 :如果在Survivor 中,相同年齡所有對象的大小總和大于 Survivor 空間的一半, 大于或等于此年齡的對象就可以直接進(jìn)入老年代。

分配擔(dān)保機(jī)制

檢查老年代最大可用連續(xù)空間 與 新生代所有對象的總空間 --> yes --> MinorGc

HandlePromotionFailure 是否允許擔(dān)保失敗 --> yes --> 檢查老年代最大可用連續(xù)空間是否大于歷次晉升到老年代對象的平均大小 --> MinorGC

2. Minor GC ,F(xiàn)ull GC 觸發(fā)條件

Minor GC觸發(fā)條件:當(dāng)Eden區(qū)滿時(shí),觸發(fā)Minor GC。
Full GC觸發(fā)條件:
(1)調(diào)用System.gc時(shí),系統(tǒng)建議執(zhí)行Full GC,但是不必然執(zhí)行
(2)老年代空間不足
(3)方法去空間不足
(4)通過Minor GC后進(jìn)入老年代的平均大小大于老年代的可用內(nèi)存
(5)由Eden區(qū)、From Space區(qū)向To Space區(qū)復(fù)制時(shí),對象大小大于To Space可用內(nèi)存,則把該對象轉(zhuǎn)存到老年代,且老年代的可用內(nèi)存小于該對象大小

3. 垃圾收集器
1. CMS (Concurrent Mark Sweep)

4個(gè)步驟:

初始標(biāo)記:標(biāo)記 GC ROOTS 可以直接關(guān)聯(lián)的對象

并發(fā)標(biāo)記:GC TRACING

重新標(biāo)記:修正并發(fā)標(biāo)記期間,用戶程序繼續(xù)動(dòng)作而導(dǎo)致的標(biāo)記產(chǎn)生變動(dòng)的那一部分對象的標(biāo)記記錄

并發(fā)清除

3個(gè)缺點(diǎn):

對 CPU 資源非常敏感

無法處理浮動(dòng)垃圾(并發(fā)清理階段,用戶線程仍舊在運(yùn)行,因此一直在產(chǎn)生垃圾,而無法在當(dāng)次收集中處理掉它們)

產(chǎn)生大量的空間碎片

2. G1 (Garbage-First)

4個(gè)特點(diǎn):

并行與并發(fā): 使用多個(gè) CPU 或 CPU 核心來縮短 Stop-The-World 停頓的時(shí)間

分代收集

空間整合: 基于標(biāo)記-整理算法

可預(yù)測的停頓: 可以建立可預(yù)測的停頓時(shí)間模型,讓使用者明確指定在一個(gè)長度為 M 毫秒的時(shí)間片段內(nèi),消耗在垃圾收集上的時(shí)間不超過 N 毫秒。

4個(gè)步驟:

初始標(biāo)記

并發(fā)標(biāo)記

最終標(biāo)記

篩選回收: 首先對各個(gè) Region 的回收價(jià)值和成本進(jìn)行排序,根據(jù)用戶所期望的 GC 停頓時(shí)間來制定回收計(jì)劃。

G1的GC模式

Young GC:選定所有年輕代里的Region。通過控制年輕代的region個(gè)數(shù),即年輕代內(nèi)存大小,來控制young GC的時(shí)間開銷。
Mixed GC:選定所有年輕代里的Region,外加根據(jù)global concurrent marking統(tǒng)計(jì)得出收集收益高的若干老年代Region。在用戶指定的開銷目標(biāo)范圍內(nèi)盡可能選擇收益高的老年代Region。

注意:Mixed GC不是full GC,它只能回收部分老年代的Region,如果mixed GC實(shí)在無法跟上程序分配內(nèi)存的速度,導(dǎo)致老年代填滿無法繼續(xù)進(jìn)行Mixed GC,就會(huì)使用serial old GC(full GC)來收集整個(gè)GC heap。

global concurrent marking:類似CMS,為Mixed GC提供標(biāo)記服務(wù)。
四個(gè)過程:

初始標(biāo)記(initial mark,STW)。它標(biāo)記了從GC Root開始直接可達(dá)的對象。

并發(fā)標(biāo)記(Concurrent Marking)。這個(gè)階段從GC Root開始對heap中的對象標(biāo)記,標(biāo)記線程與應(yīng)用程序線程并行執(zhí)行,并且收集各個(gè)Region的存活對象信息。

最終標(biāo)記(Remark,STW)。標(biāo)記那些在并發(fā)標(biāo)記階段發(fā)生變化的對象,將被回收。

清除垃圾(Cleanup)。清除空Region(沒有存活對象的),加入到free list。

G1 中的幾個(gè)重要概念 -- 原文鏈接--美團(tuán)點(diǎn)評

一、Region

傳統(tǒng)的GC收集器將連續(xù)的內(nèi)存空間劃分為新生代、老年代和永久代(JDK 8去除了永久代,引入了元空間Metaspace),這種劃分的特點(diǎn)是各代的存儲(chǔ)地址(邏輯地址,下同)是連續(xù)的。

如下圖所示:

而G1的各代存儲(chǔ)地址是不連續(xù)的,每一代都使用了n個(gè)不連續(xù)的大小相同的Region,每個(gè)Region占有一塊連續(xù)的虛擬內(nèi)存地址。如下圖所示:

在上圖中,我們注意到還有一些Region標(biāo)明了H,它代表Humongous,這表示這些Region存儲(chǔ)的是巨大對象(humongous object,H-obj),即大小大于等于region一半的對象。H-obj有如下幾個(gè)特征:

H-obj直接分配到了old gen (老年代),防止了反復(fù)拷貝移動(dòng)。

H-obj在global concurrent marking 階段的 cleanupfull GC 階段回收。

在分配H-obj之前先檢查是否超過 initiating heap occupancy percent和the marking threshold, 如果超過的話,就啟動(dòng) global concurrent marking,為的是提早回收,防止 evacuation failures 和 full GC。
為了減少連續(xù)H-objs分配對GC的影響,需要把大對象變?yōu)槠胀ǖ膶ο?,建議增大Region size。

二、SATB

全稱是Snapshot-At-The-Beginning,由字面理解,是GC開始時(shí)活著的對象的一個(gè)快照。它是通過Root Tracing得到的,作用是維持并發(fā)GC的正確性。

那么它是怎么維持并發(fā)GC的正確性的呢?根據(jù)三色標(biāo)記算法,我們知道對象存在三種狀態(tài):

白:對象沒有被標(biāo)記到,標(biāo)記階段結(jié)束后,會(huì)被當(dāng)做垃圾回收掉。

灰:對象被標(biāo)記了,但是它的field還沒有被標(biāo)記或標(biāo)記完。

黑:對象被標(biāo)記了,且它的所有field也被標(biāo)記完了。

由于并發(fā)階段的存在,Mutator(更改器和)Garbage Collector線程同時(shí)對對象進(jìn)行修改,就會(huì)出現(xiàn)白對象漏標(biāo)的情況,這種情況發(fā)生的前提是:

Mutator賦予一個(gè)黑對象該白對象的引用。

Mutator刪除了所有從灰對象到該白對象的直接或者間接引用。

對于第一個(gè)條件,在并發(fā)標(biāo)記階段,如果該白對象是new出來的,并沒有被灰對象持有,那么它會(huì)不會(huì)被漏標(biāo)呢?Region中有兩個(gè)top-at-mark-start(TAMS)指針,分別為prevTAMS和nextTAMS。在TAMS以上的對象是新分配的,這是一種隱式的標(biāo)記。
對于在GC時(shí)已經(jīng)存在的白對象,如果它是活著的,它必然會(huì)被另一個(gè)對象引用,即條件二中的灰對象。如果灰對象到白對象的直接引用或者間接引用被替換了,或者刪除了,白對象就會(huì)被漏標(biāo),從而導(dǎo)致被回收掉,這是非常嚴(yán)重的錯(cuò)誤,所以SATB破壞了第二個(gè)條件。
也就是說,一個(gè)對象的引用被替換時(shí),可以通過 write barrier 將舊引用記錄下來。(并沒有 看懂在說什么)

SATB也是有副作用的,如果被替換的白對象就是要被收集的垃圾,這次的標(biāo)記會(huì)讓它躲過GC,這就是float garbage。因?yàn)镾ATB的做法精度比較低,所以造成的float garbage也會(huì)比較多。

三、RSet

全稱是Remembered Set,是輔助GC過程的一種結(jié)構(gòu),典型的空間換時(shí)間工具,和Card Table有些類似。
還有一種數(shù)據(jù)結(jié)構(gòu)也是輔助GC的:Collection Set(CSet),它記錄了 GC要收集的Region集合 ,集合里的Region可以是任意年代的。
在GC的時(shí)候,對于old->young和old->old的跨代對象引用,只要掃描對應(yīng)的CSet中的RSet即可。

Rset : 屬于points-into結(jié)構(gòu)(誰引用了我的對象)
Card Table : 則是一種points-out(我引用了誰的對象)的結(jié)構(gòu)
G1的RSet是在Card Table的基礎(chǔ)上實(shí)現(xiàn)的:每個(gè)Region會(huì)記錄下別的Region有指向自己的指針,并標(biāo)記這些指針分別在哪些Card的范圍內(nèi)。
這個(gè)RSet其實(shí)是一個(gè)Hash Table,Key -- 別的Region的起始地址Value是一個(gè)集合 -- 里面的元素是Card Table的Index。

這里解釋一下 :
上圖有三個(gè) Region 。紅色代表 Rset , 灰色大方框代表 Card Table。
Region2 的 Rset2 中有兩個(gè) Region 的起始地址,分別指向 Region1 , Region3。 -- 代表 Region1 與 Region3 引用了我的對象。
Region1 的 Card Table 位置上,存在一個(gè) 對 Region2 的引用。 -- 代表 Region1 引用了 Region2 的對象。
Region3 同理。

作用:
在做YGC(Minor GC)的時(shí)候,只需要選定young generation region的RSet作為根集,這些RSet記錄了old->young的跨代引用,避免了掃描整個(gè)old generation。
而mixed gc的時(shí)候,old generation中記錄了old->old的RSet,young->old的引用由掃描全部young generation region得到,這樣也不用掃描全部old generation region。所以RSet的引入大大減少了GC的工作量。

四、Pause Prediction Model

G1 uses a pause prediction model to meet a user-defined pause time target and selects the number of regions to collect based on the specified pause time target.

G1 GC是一個(gè)響應(yīng)時(shí)間優(yōu)先的GC算法,它與CMS最大的不同是,用戶可以設(shè)定整個(gè)GC過程的期望停頓時(shí)間,參數(shù)"-XX:MaxGCPauseMillis"指定一個(gè)G1收集過程目標(biāo)停頓時(shí)間,默認(rèn)值200ms。
G1 通過這個(gè)模型統(tǒng)計(jì)計(jì)算出來的歷史數(shù)據(jù)來預(yù)測本次收集需要選擇的Region數(shù)量,從而盡量滿足用戶設(shè)定的目標(biāo)停頓時(shí)間。
停頓預(yù)測模型是以衰減標(biāo)準(zhǔn)偏差為理論基礎(chǔ)實(shí)現(xiàn)的。
這里就不詳細(xì)介紹了,有興趣的,可以看 美團(tuán)大神的文章

4.2 Java 內(nèi)存

程序計(jì)數(shù)器

虛擬機(jī)棧 : 局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口

本地方法棧 : native 方法

堆 : 所有的對象實(shí)例以及數(shù)組

方法區(qū) : 已被加載的類信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼

運(yùn)行時(shí)常量池 : 編譯期生成的各種字面量和符號引用

直接內(nèi)存 : NIO類引入了一種基于通道(channel) 與 緩沖區(qū)(buffer) 的 I/O 方式,使用 Native 函數(shù)庫直接分配堆外內(nèi)存 , 通過存儲(chǔ)在 Java 堆中的 DirectByteBuffer 對象作為這塊內(nèi)存的引用進(jìn)行操作。

1. Java 對象的內(nèi)存布局

對象頭 : 哈希碼(2bit)-分代年齡(4)、輕量級鎖定(標(biāo)志位 00)、重量級鎖定、GC標(biāo)記、可偏向(標(biāo)志位 01),補(bǔ)充: 類型指針、數(shù)組長度

實(shí)例數(shù)據(jù) :

對齊填充

2. OOM 異常

堆溢出: 不斷創(chuàng)建對象,并且存在可達(dá)路徑,不被清除。那么對象在達(dá)到最大堆容量限制后就會(huì)產(chǎn)生內(nèi)存溢出
通過 內(nèi)存映像分析工具 (Eclipse Memory Analyzer) 對 Dump 出來的堆轉(zhuǎn)存儲(chǔ)快照進(jìn)行分析。判斷是內(nèi)存泄漏還是內(nèi)存溢出。

虛擬機(jī)棧與本地方法棧溢出:
如果線程請求的棧深度大于虛擬機(jī)所允許的最大深度,將拋出 StackOverFlowError 異常。

如果虛擬機(jī)在擴(kuò)展棧時(shí)無法申請到足夠的內(nèi)存空間,則拋出 OutOfMemoryError 異常。

方法區(qū)
方法區(qū)存放 Class 的相關(guān)信息。如果存在大量的類 填滿 方法區(qū)。則會(huì)產(chǎn)生溢出。

通過 動(dòng)態(tài)代理 或 通過 CGLIB 動(dòng)態(tài)生成大量的類,以及大量 JSP與 動(dòng)態(tài)JSP 文件的應(yīng)用 。

3. OOM 異常的解決

一. 可通過命令定期抓取heap dump或者啟動(dòng)參數(shù)OOM時(shí)自動(dòng)抓取heap dump文件。
二. 通過對比多個(gè)heap dump,以及heap dump的內(nèi)容,分析代碼找出內(nèi)存占用最多的地方。
三. 分析占用的內(nèi)存對象,是否是因?yàn)殄e(cuò)誤導(dǎo)致的內(nèi)存未及時(shí)釋放,或者數(shù)據(jù)過多導(dǎo)致的內(nèi)存溢出。

4.3 類加載器 1. 類加載過程

加載 :可以通過自定義類加載器參與

通過一個(gè)類的全限定名獲取定義此類的二進(jìn)制字節(jié)流

將這個(gè)字節(jié)流代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)

在內(nèi)存中生成一個(gè)代表這個(gè)類的 java.lang.Class 對象,作為方法區(qū)這個(gè)類的各種數(shù)據(jù)的訪問入口

驗(yàn)證

文件格式驗(yàn)證

元數(shù)據(jù)驗(yàn)證 : 語義校驗(yàn)

字節(jié)碼驗(yàn)證 :邏輯校驗(yàn)

符號引用驗(yàn)證 :發(fā)生在解析階段中,將符號引用轉(zhuǎn)化為直接引用

準(zhǔn)備 : 為類變量分配內(nèi)存并設(shè)置類變量初始值的階段

解析 : 將符號引用 替換 為直接引用的過程。

初始化 : () 類構(gòu)造器 : 將類中的賦值語句與靜態(tài)代碼塊合并而成 -- () 實(shí)例構(gòu)造器

2. 雙親委派模型

  啟動(dòng)(Bootstrap)類加載器:采用 C++ 實(shí)現(xiàn),它負(fù)責(zé)將 /lib下面的核心類庫或-Xbootclasspath選項(xiàng)指定的jar包加載到內(nèi)存中。由于啟動(dòng)類加載器到本地代碼的實(shí)現(xiàn),開發(fā)者無法直接獲取到啟動(dòng)類加載器的引用,所以不允許直接通過引用進(jìn)行操作。編寫自定義類加載器時(shí),如果需要把加載請求委派給啟動(dòng)類加載器,直接使用 null 代替.
  擴(kuò)展(Extension)類加載器:擴(kuò)展類加載器是由Sun的ExtClassLoader(sun.misc.Launcher$ExtClassLoader)實(shí)現(xiàn)的。它負(fù)責(zé)將< Java_Runtime_Home >/lib/ext或者由系統(tǒng)變量-Djava.ext.dir指定位置中的類庫加載到內(nèi)存中。開發(fā)者可以直接使用標(biāo)準(zhǔn)擴(kuò)展類加載器。
  系統(tǒng)(System)類加載器:系統(tǒng)類加載器是由 Sun的 AppClassLoader(sun.misc.Launcher$AppClassLoader)實(shí)現(xiàn)的。它負(fù)責(zé)將系統(tǒng)類路徑j(luò)ava -classpath或-Djava.class.path變量所指的目錄下的類庫加載到內(nèi)存中。開發(fā)者可以直接使用系統(tǒng)類加載器。

工作過程:
如果一個(gè)類加載器收到了類的加載的請求,它首先不會(huì)自己去嘗試加載這個(gè)類,而是把這個(gè)請求委派給父類加載器去完成。直到頂層的啟動(dòng)類加載器中,當(dāng)父加載器反饋?zhàn)约簾o法完成這個(gè)加載請求時(shí),子加載器會(huì)嘗試自己去加載。

3. 線程上下文類加載器

方便 JNDI 服務(wù):SPI 的接口是 Java 核心庫的一部分,是由引導(dǎo)類加載器來加載的;SPI 實(shí)現(xiàn)的 Java 類一般是由系統(tǒng)類加載器來加載的。引導(dǎo)類加載器是無法找到 SPI 的實(shí)現(xiàn)類的,因?yàn)樗患虞d Java 的核心庫。它也不能代理給系統(tǒng)類加載器,因?yàn)樗窍到y(tǒng)類加載器的祖先類加載器。也就是說,類加載器的代理模式無法解決這個(gè)問題。
解決方法:Java 應(yīng)用的線程的上下文類加載器 默認(rèn) 就是系統(tǒng)上下文類加載器。在 SPI 接口的代碼中使用線程上下文類加載器,就可以成功的加載到 SPI 實(shí)現(xiàn)的類。線程上下文類加載器在很多 SPI 的實(shí)現(xiàn)中都會(huì)用到。
Java默認(rèn)的線程上下文類加載器是系統(tǒng)類加載器(AppClassLoader)。以下代碼摘自sun.misc.Launch的無參構(gòu)造函數(shù)Launch()。
可以通過 java.lang.Thread類 的 setContextClassLoader() 設(shè)置。

4. OSGI(open service gataway initiative)

方便執(zhí)部署的實(shí)現(xiàn)。可以在不重啟服務(wù)器的情況下,對其中的邏輯代碼進(jìn)行更新。
由 父類加載器 與 Bundle 組成 , 每個(gè) Bundle 的功能都是 發(fā)布 export 與依賴 import。從而形成復(fù)雜的網(wǎng)狀結(jié)構(gòu)
原理:
OSGi 中的每個(gè)模塊都有對應(yīng)的一個(gè)類加載器。它負(fù)責(zé)加載模塊自己包含的 Java 包和類。
當(dāng)它需要加載 Java 核心庫的類時(shí)(以 java開頭的包和類),它會(huì)代理給父類加載器(通常是啟動(dòng)類加載器)來完成。
當(dāng)它需要加載所導(dǎo)入的 Java 類時(shí),它會(huì)代理給導(dǎo)出此 Java 類的模塊來完成加載。

5. Tomcat

在雙親委派模型的基礎(chǔ)上加入了 Common類加載器,Catalina類加載器,Shared類加載器,WebApp類加載器,Jsp類加載器
Common類加載器, /common 目錄 被 Tomcat 與 所以 Web 應(yīng)用程序共同使用
Catalina類加載器, /server 目錄中, 被 Tomcat 使用
Shared類加載器, /shared 目錄中 ,被所有 Web 應(yīng)用程序共同使用
WebApp類加載器,Jsp類加載器 , /WebApp/WEB-INF 目錄中,只能被此 Web 應(yīng)用程序使用。

4.4 解釋器與編譯器 1. 編譯模式

Mixed Mode -- 混合模式
默認(rèn)為混合模式,解釋器與編譯器搭配使用。

Interpreted Mode -- 解釋模式
使用 “-Xint" 參數(shù)。只使用解釋。

Compiled Mode -- 編譯模式
使用 “-Xcomp" 參數(shù)。 優(yōu)先采用編譯,當(dāng)編譯無法進(jìn)行時(shí),使用解釋。

-version 命令,可以輸出顯示這三種模式

2. 分層編譯(Tiered Compilation)

JDK1.7 中的 Server 模式虛擬機(jī)中被作為默認(rèn)編譯策略。

0層,程序解釋執(zhí)行,解釋器不開啟性能監(jiān)控功能(Profiling),可觸發(fā)第一層編譯

1層,也叫C1 編譯(下文有解釋),將字節(jié)碼編譯為本地代碼,進(jìn)行簡單、可靠的優(yōu)化

2層,C2編譯。

3. OSR編譯

因?yàn)榇嬖诙啻螆?zhí)行的循環(huán)體,所以觸發(fā) OSR 編譯,以整個(gè)方法 作為編譯對象。
發(fā)生在方法執(zhí)行過程中,所以叫( On Stack Replacement ) 方法棧幀還在棧上,方法就被替換了。

4. 編譯對象以及觸發(fā)條件

熱點(diǎn)代碼的分類:

被多次調(diào)用的方法

被多次執(zhí)行的方法體 -- OSR 編譯

熱點(diǎn)探測(Hot Spot Detection)

基于采樣 : 如果周期性的檢查各個(gè)線程的棧頂,如果發(fā)現(xiàn)某個(gè)方法經(jīng)常出現(xiàn)在棧頂,則這個(gè)方法就是“熱點(diǎn)方法”。

基于計(jì)數(shù)器 -- HotSpot 虛擬機(jī)中采用。

原理: 為每個(gè)方法建立計(jì)數(shù)器,統(tǒng)計(jì)方法的次數(shù),如果執(zhí)行次數(shù)超過一定的閾值,就認(rèn)為它是“熱點(diǎn)方法”

計(jì)數(shù)器分類:

方法調(diào)用計(jì)數(shù)器(Invocation Counter) :

**統(tǒng)計(jì)一段時(shí)間內(nèi)**,方法被調(diào)用的次數(shù),如果超過時(shí)間限度,則將這個(gè)方法的調(diào)用計(jì)數(shù)器減少一半,稱為**衰減**

回邊計(jì)數(shù)器(Back Edge Counter) : 統(tǒng)計(jì)一個(gè)方法中循環(huán)體被執(zhí)行的次數(shù) -- OSR 編譯

在字節(jié)碼中遇到控制流向后跳轉(zhuǎn)的指令,稱為回邊。

5. 優(yōu)化措施

hotspot中內(nèi)嵌有2個(gè)JIT編譯器,分別為Client Compiler,Server Compiler,但大多數(shù)情況下我們稱之為C1編譯器和C2編譯器。

5.1 C1 編譯器

client compiler,又稱C1編譯器,較為輕量,只做少量性能開銷比較高的優(yōu)化,它占用內(nèi)存較少,適合于桌面交互式應(yīng)用。
在寄存器分配策略上,JDK6以后采用的為線性掃描寄存器分配算法,其他方面的優(yōu)化,主要有方法內(nèi)聯(lián)、去虛擬化、冗余消除等。

A、方法內(nèi)聯(lián)

多個(gè)方法調(diào)用,執(zhí)行時(shí)要經(jīng)歷多次參數(shù)傳遞,返回值傳遞及跳轉(zhuǎn)等,C1采用方法內(nèi)聯(lián),把調(diào)用到的方法的指令直接植入當(dāng)前方法中。-XX:+PringInlining來查看方法內(nèi)聯(lián)信息,-XX:MaxInlineSize=35控制編譯后文件大小。

B、去虛擬化

是指在裝載class文件后,進(jìn)行類層次的分析,如果發(fā)現(xiàn)類中的方法只提供一個(gè)實(shí)現(xiàn)類,那么對于調(diào)用了此方法的代碼,也可以進(jìn)行方法內(nèi)聯(lián),從而提升執(zhí)行的性能。

C、冗余消除

在編譯時(shí)根據(jù)運(yùn)行時(shí)狀況進(jìn)行代碼折疊或消除。

5.2 C2 編譯器

Server compiler,稱為C2編譯器,較為重量,采用了大量傳統(tǒng)編譯優(yōu)化的技巧來進(jìn)行優(yōu)化,占用內(nèi)存相對多一些,適合服務(wù)器端的應(yīng)用。和C1的不同主要在于寄存器分配策略及優(yōu)化范圍.
寄存器分配策略上C2采用的為傳統(tǒng)的圖著色寄存器分配算法,由于C2會(huì)收集程序運(yùn)行信息,因此其優(yōu)化范圍更多在于全局優(yōu)化,不僅僅是一個(gè)方塊的優(yōu)化。
收集的信息主要有:分支的跳轉(zhuǎn)/不跳轉(zhuǎn)的頻率、某條指令上出現(xiàn)過的類型、是否出現(xiàn)過空值、是否出現(xiàn)過異常等。

逃逸分析(Escape Analysis) 是C2進(jìn)行很多優(yōu)化的基礎(chǔ),它根據(jù)運(yùn)行狀態(tài)來判斷方法中的變量是否會(huì)被外部讀取,如不會(huì)則認(rèn)為此變量是不會(huì)逃逸的,那么在編譯時(shí)會(huì)做標(biāo)量替換、棧上分配和同步消除等優(yōu)化。
如果證明一個(gè)對象不會(huì)逃逸到方法或線程之外,則:

- 棧上分配(Stack Allocation) :確定不會(huì)逃逸到**方法外**,讓這個(gè)對象在棧上分配內(nèi)存,對象占用的內(nèi)存空間可以隨棧幀的出棧而銷毀。
- 同步消除(Synchronization Elimination) :確定不會(huì)逃逸到**線程外**,則無法被其他線程訪問,所以可以取消同步措施。
- 標(biāo)量替換(Scalar Repalcement) : 
    標(biāo)量(Scalar)指一個(gè)數(shù)據(jù)無法再分解成更小的數(shù)據(jù)來表示 -- Java 中的原始數(shù)據(jù)類型
    聚合量(Aggregate)指一個(gè)數(shù)據(jù)可以繼續(xù)分解 -- Java 中的對象
    **原理:**直接創(chuàng)建若干個(gè)可以被方法使用的成員變量來替代。
5.3 其他措施(注: 不知是 C1 還是 C2)

語言無關(guān)的經(jīng)典優(yōu)化技術(shù) -- 公共子表達(dá)式消除(Common Subexpression Elimination)

如果一個(gè)表達(dá)式E 已經(jīng)計(jì)算過,并且從先前的計(jì)算 到現(xiàn)在 值未曾改變,那么如果 E 再次出現(xiàn),則可以直接使用之前的表達(dá)式結(jié)果,代替 E 。

語言相關(guān)的經(jīng)典優(yōu)化技術(shù) -- 數(shù)組邊界檢查消除(Array Bounds Checking Elimination)
這個(gè)不是很了解,做一個(gè)重點(diǎn)。。。 以后整理

4. 零散知識(shí)點(diǎn) 1. 靜態(tài)多分派與動(dòng)態(tài)單分派

靜態(tài)分派 : 依靠靜態(tài)類型 定位方法。
編譯階段:Human man = new Man(); // 靜態(tài)類型為 Human
運(yùn)行階段:man.sayHello() // 動(dòng)態(tài)類型為 Man

重載的優(yōu)先級
sayHello(char arg);
char -> int -> long -> float -> double // 不可轉(zhuǎn)化為 byte short , 因?yàn)閏har 轉(zhuǎn)化是不安全的。
-> Character -> Serializable/Comparable -> Object -> char...(變長參數(shù))

宗量:方法的接收者與方法的參數(shù)統(tǒng)稱為宗量
單分派 根據(jù)一個(gè)宗量對目標(biāo)方法進(jìn)行選擇
多分派 根據(jù)多個(gè)宗量對目標(biāo)方法進(jìn)行選擇

public class QQ{};
public class _360{};
public static class Father {
    public void hardChoice(QQ arg);
    public void hardChoice(_360 arg);
}
public static class Son extends Father{
    public void hardChoice(QQ arg);
    public void hardChoice(_360 arg);
}

Father father = new Father();
Father son = new Son();

// 靜態(tài)多分派 - 編譯 : 方法的接收者 Father - Son, 參數(shù) QQ - _360
father.hardChoice(_360);
// 動(dòng)態(tài)多分派 - 運(yùn)行 : 已經(jīng)確定 參數(shù)為 QQ ,再判斷 實(shí)際類型 , son的實(shí)際類型為 Son 。
son.hardChoice(QQ);
結(jié)語

都看到這里了,點(diǎn)個(gè)關(guān)注,點(diǎn)波再走,QAQ。
你的小手輕點(diǎn),是我最大的動(dòng)力哦。

一只想當(dāng)程序員的1米88處女座大可愛如此說道。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/67768.html

相關(guān)文章

  • 跨越逐夢路上的荊棘(程序猿生存)

    摘要:曾經(jīng)的小學(xué)生,初中生現(xiàn)如今已是社會(huì)的中流砥柱。一個(gè)互聯(lián)網(wǎng)公司要正常運(yùn)作,必定就需要一群足智多謀,思維敏捷,邏輯縝密的程序猿。這群能力超凡的人類,其實(shí)也有不堪一擊的致命弱點(diǎn)。同時(shí)我們也該擁有同等的尊重。 時(shí)光荏苒,歲月如梭。曾經(jīng)的小學(xué)生,初中生現(xiàn)如今已是社會(huì)的中流砥柱。隨著科技時(shí)代的迅猛發(fā)展,曾經(jīng)的荒土,已是星羅棋布高樓聳立。其中不乏科技相關(guān)的樓宇,俗稱互聯(lián)網(wǎng)公司。也許你,現(xiàn)在就正處于其...

    CastlePeaK 評論0 收藏0
  • 跨越逐夢路上的荊棘(程序猿生存)

    摘要:曾經(jīng)的小學(xué)生,初中生現(xiàn)如今已是社會(huì)的中流砥柱。一個(gè)互聯(lián)網(wǎng)公司要正常運(yùn)作,必定就需要一群足智多謀,思維敏捷,邏輯縝密的程序猿。這群能力超凡的人類,其實(shí)也有不堪一擊的致命弱點(diǎn)。同時(shí)我們也該擁有同等的尊重。 時(shí)光荏苒,歲月如梭。曾經(jīng)的小學(xué)生,初中生現(xiàn)如今已是社會(huì)的中流砥柱。隨著科技時(shí)代的迅猛發(fā)展,曾經(jīng)的荒土,已是星羅棋布高樓聳立。其中不乏科技相關(guān)的樓宇,俗稱互聯(lián)網(wǎng)公司。也許你,現(xiàn)在就正處于其...

    Barry_Ng 評論0 收藏0
  • 2017-10-16 前端日報(bào)

    摘要:前端日報(bào)精選譯發(fā)布了王躍關(guān)于微信小程序的技術(shù),也許你想錯(cuò)了細(xì)說中的瀏覽器頁面渲染工作原理淺析騰訊前端團(tuán)隊(duì)社區(qū)中文第期安息吧,長存譯借助函數(shù)完成可組合的數(shù)據(jù)類型軟件編寫第十部分掘金對象與原型掘金技術(shù)周刊期知乎專欄是真正的語言 2017-10-16 前端日報(bào) 精選 [譯]Vue 2.5 發(fā)布了王躍:關(guān)于微信小程序的技術(shù),也許你想錯(cuò)了細(xì)說Web API中的Blobchrome瀏覽器頁面渲染工...

    molyzzx 評論0 收藏0
  • 我的阿里之路+Java面經(jīng)考點(diǎn)

    摘要:我的是忙碌的一年,從年初備戰(zhàn)實(shí)習(xí)春招,年三十都在死磕源碼,三月份經(jīng)歷了阿里五次面試,四月順利收到實(shí)習(xí)。因?yàn)槲倚睦砗芮宄?,我的目?biāo)是阿里。所以在收到阿里之后的那晚,我重新規(guī)劃了接下來的學(xué)習(xí)計(jì)劃,將我的短期目標(biāo)更新成拿下阿里轉(zhuǎn)正。 我的2017是忙碌的一年,從年初備戰(zhàn)實(shí)習(xí)春招,年三十都在死磕JDK源碼,三月份經(jīng)歷了阿里五次面試,四月順利收到實(shí)習(xí)offer。然后五月懷著忐忑的心情開始了螞蟻金...

    姘擱『 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<