黑馬程序員JVM完整教程,Java虛擬機(jī)快速入門,全程干貨不拖沓









棧幀過多

棧幀過大



Java虛擬機(jī)有一個(gè)方法區(qū),是所有Java虛擬之間共享機(jī)線程。
方法區(qū)域類似于編譯代碼的存儲區(qū)域
傳統(tǒng)的語言或類似于“文本”段在一個(gè)操作系統(tǒng)
的過程。
它存儲每個(gè)類結(jié)構(gòu)運(yùn)行時(shí)常量池等領(lǐng)域
方法數(shù)據(jù)和方法和構(gòu)造函數(shù)的代碼,包括特別
方法用于類和實(shí)例初始化和接口初始化。
方法區(qū)上創(chuàng)建虛擬機(jī)啟動的方法。
雖然方法區(qū)邏輯上堆的一部分,簡單的實(shí)現(xiàn)可以選擇不垃圾收集或緊湊。
本規(guī)范并不強(qiáng)制的位置的方法

·1.8以前會導(dǎo)致永久代內(nèi)存溢出
·1.8之后會導(dǎo)致元空間內(nèi)存溢出




記住new 都是堆內(nèi)存

永久代回收效率低
直接內(nèi)存! gc不能 unsafe

垃圾回收
GCROOTs




https://blog.csdn.net/linzhiqiang0316/article/details/88591907
https://blog.csdn.net/weixin_43338519/article/details/107836096

參數(shù)配置

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



gc 調(diào)優(yōu)


越大時(shí)間也會越長

初始標(biāo)記:僅僅標(biāo)記GC ROOTS的直接關(guān)聯(lián)對象,并且世界暫停??
并發(fā)標(biāo)記:使用GC ROOTS TRACING算法,進(jìn)行跟蹤標(biāo)記,世界不暫停
重新標(biāo)記,因?yàn)橹安l(fā)標(biāo)記,其他用戶線程不暫停,可能產(chǎn)生了新垃圾,所以重新標(biāo)記,世界暫停??
- 新生代 GC(Minor GC):指發(fā)生新生代的的垃圾收集動作,Minor GC 非常頻繁,回收速度一般也比較快。
- 老年代 GC(Major GC/Full GC):指發(fā)生在老年代的 GC,出現(xiàn)了 Major GC 經(jīng)常會伴隨至少一次的 Minor GC(并非絕對),Major GC 的速度一般會比 Minor GC 的慢 10 倍以上。
重新標(biāo)記錢 先清理



附加屬性_計(jì)數(shù);






字節(jié)碼一樣



靜態(tài)代碼>構(gòu)造方法
父>子
int


編譯類型看左邊 運(yùn)行類型看右邊

跟上例中的finally相比,發(fā)現(xiàn)沒有athrow了,這告訴我們:如果在finally中出現(xiàn)了 return, 會吞掉異常,可以試一下下面的代碼!!!
原來就是把要返回的值先保存到局部變量中,返回前再load到棧中返回
return 不受影響


一開始是new指令在堆上分配了內(nèi)存并向操作數(shù)棧壓入了指向這段內(nèi)存的引用,之后dup指令又備份了一份,那么操作數(shù)棧頂就有兩個(gè),再后是調(diào)用invokespecial #18指令進(jìn)行初始化,此時(shí)會消耗一個(gè)引用作為傳給構(gòu)造器的“this”參數(shù),那么還剩下一個(gè)引用,會被astore_1指令存儲當(dāng)然new之后有時(shí)候會執(zhí)行<init>,這主要依據(jù)字節(jié)碼中是否包含invokespecial指令。下面主要說一下該指令
主要目的:得到對象存在堆中的地址,這樣就可以用當(dāng)前類,父類,父父類,即繼承層的所有對象。??把繼承層的所有對象的數(shù)據(jù)和方法為自己當(dāng)前對象使用。到局部變量表中。

編譯器處理
-127 -128 不會new


數(shù)組:直接fori

集合:迭代器

兩次switch 防止hash沖突


JDKT開始新增了對需要關(guān)閉的資源處理的特殊語法try-with-resources:







final直接賦值
cinit 靜態(tài)成員變量復(fù)制 初始化階段/
將常量池中的符號引用解析為直接引用
字符串->地址
在類初始化之前的準(zhǔn)備階段,虛擬機(jī)會將類變量(static 修飾的變量)分配內(nèi)存并設(shè)置零值。
在類初始化階段,執(zhí)行類構(gòu)造器 <cinit>() 方法。<cinit> 類初始化方法有如下特點(diǎn):
編譯器會在將 .java 文件編譯成 .class 文件時(shí),收集所有類初始化代碼和 static {} 域的代碼,收集在一起成為 <cinit>() 方法;
子類初始化時(shí)會首先調(diào)用父類的 <cinit>() 方法;
JVM 會保證 <cinit>() 方法的線程安全,保證同一時(shí)間只有一個(gè)線程執(zhí)行;


老師這個(gè)靜態(tài)內(nèi)部類利用的巧妙,調(diào)用Singleton函數(shù),不會觸發(fā)這個(gè)靜態(tài)內(nèi)部類的初始化,也就是不會創(chuàng)建這個(gè)單例對象

啟動類加載路徑

默認(rèn)是使用本來的加載器加載依賴類的
由于JDBC在核心類庫中,它由啟動類加載器加載,由于驅(qū)動是在他的類初始化方法中加載的
于是要顯示的調(diào)用Classd的forName方法使用一個(gè)能加載驅(qū)動的加載器加載驅(qū)動
1、我來總結(jié)下,在jre/lib包下有一個(gè)DriverManager,是啟動類加載的,但是jdbc的驅(qū)動是各個(gè)廠商來實(shí)現(xiàn)的不在啟動類加載路徑下,啟動類無法加載,而驅(qū)動管理需要用到這些驅(qū)動
1、SPI機(jī)制能夠使接口與具體的實(shí)現(xiàn)類解耦, 可以根據(jù)實(shí)際的
業(yè)務(wù)情況啟用或替換具體組件。
2、SPI機(jī)制為很多框架的擴(kuò)展提供了可能。
3、SPI機(jī)制更多的是一種思想
3、過程就是:啟動類加載器加載DriverManager,DriverManager代碼里調(diào)用了線程上下文類加載器,這個(gè)加載器默認(rèn)就是使用應(yīng)用程序類加載器加載類,通過應(yīng)用程序類加載器加載jdbc驅(qū)動

jmm



synchronized語句塊既可以保證代碼塊的原子性,也同時(shí)保證代碼塊內(nèi)變量的可見性。但缺點(diǎn)是
synchronized是屬于重量級操作,性能相對更低

對iNSTANCE使用volatile修飾即可,可以禁用指令重排,但要注意在DK5以上的版本的volatile才會真正有效
CAS即Compare and Swap.,它體現(xiàn)的一種樂觀鎖的思想 與 volatile(易變的)

樂觀鎖與悲觀鎖
CAS是基于樂觀鎖的思想:最樂觀的估計(jì),不怕別的線程來修改共享變量,就算改了也設(shè)關(guān)系,我吃虧點(diǎn)再重試唄。
synchronized是基于悲觀鎖的思想:最悲觀的估計(jì),得防著其它線程來修改共享變量,我上了鎖你們都別想改,我改完了解開鎖,你們才有機(jī)會。
juc (java.util.concurent)中提供了原子操作類,可以提供線程安全的操作,例如:AtomicInteger、AtomicBoolean等,它們底層就是采用CAS技術(shù)+volatile來實(shí)現(xiàn)的。




重量級鎖沒事,解鎖就是

自旋成功

自旋失敗會放棄
