国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

這篇具有很好參考價(jià)值的文章主要介紹了java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

虛擬機(jī)篇

1. JVM 內(nèi)存結(jié)構(gòu)

要求

  • 掌握 JVM 內(nèi)存結(jié)構(gòu)劃分
  • 尤其要知道方法區(qū)、永久代、元空間的關(guān)系

結(jié)合一段 java 代碼的執(zhí)行理解內(nèi)存劃分

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize


java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  • 執(zhí)行 javac 命令編譯源代碼為字節(jié)碼
  • 執(zhí)行 java 命令
    1. 創(chuàng)建 JVM,調(diào)用類加載子系統(tǒng)加載 class,將類的信息存入方法區(qū)
    2. 創(chuàng)建 main 線程,使用的內(nèi)存區(qū)域是 JVM 虛擬機(jī)棧,開始執(zhí)行 main 方法代碼
    3. 如果遇到了未見過(guò)的類,會(huì)繼續(xù)觸發(fā)類加載過(guò)程,同樣會(huì)存入方法區(qū)
    4. 需要?jiǎng)?chuàng)建對(duì)象,會(huì)使用內(nèi)存來(lái)存儲(chǔ)對(duì)象
    5. 不再使用的對(duì)象,會(huì)由垃圾回收器在內(nèi)存不足時(shí)回收其內(nèi)存
    6. 調(diào)用方法時(shí),方法內(nèi)的局部變量、方法參數(shù)所使用的是 JVM 虛擬機(jī)棧中的棧幀內(nèi)存
    7. 調(diào)用方法時(shí),先要到方法區(qū)獲得到該方法的字節(jié)碼指令,由解釋器將字節(jié)碼指令解釋為機(jī)器碼執(zhí)行
    8. 調(diào)用方法時(shí),會(huì)將要執(zhí)行的指令行號(hào)讀到程序計(jì)數(shù)器,這樣當(dāng)發(fā)生了線程切換,恢復(fù)時(shí)就可以從中斷的位置繼續(xù)
    9. 對(duì)于非 java 實(shí)現(xiàn)的方法調(diào)用,使用內(nèi)存稱為本地方法棧(見說(shuō)明)
    10. 對(duì)于熱點(diǎn)方法調(diào)用,或者頻繁的循環(huán)代碼,由 JIT 即時(shí)編譯器將這些代碼編譯成機(jī)器碼緩存,提高執(zhí)行性能 (否則每次執(zhí)行相同的代碼,都要解釋器重復(fù)地將字節(jié)碼指令解釋為機(jī)器碼執(zhí)行,相當(dāng)于對(duì)字節(jié)碼指令做了緩存)

方法區(qū):存放類的相關(guān)信息(類的名稱、繼承關(guān)系、引用的其他類的符號(hào)、成員變量、方法的字節(jié)碼、類和方法和成員變量上加的注解等等)
堆: 存放new出來(lái)的對(duì)象
JVM 虛擬機(jī)棧:存放方法內(nèi)的局部變量和方法參數(shù) java實(shí)現(xiàn)的普通方法變量都存在這里,以前需要和os交互的特殊方法需要到本地方法棧去執(zhí)行,但是現(xiàn)在Oracle公司的 Hotspot 虛擬機(jī)實(shí)現(xiàn)已經(jīng)不再使用本地方法棧,或者說(shuō)兩個(gè)棧合二為一了,所有方法需要的變量?jī)?nèi)存都在JVM 虛擬機(jī)棧中

說(shuō)明

  • 加粗字體代表了 JVM 虛擬機(jī)組件
  • 對(duì)于 Oracle 的 Hotspot 虛擬機(jī)實(shí)現(xiàn),不區(qū)分虛擬機(jī)棧和本地方法棧

會(huì)發(fā)生內(nèi)存溢出的區(qū)域

內(nèi)存溢出: 該區(qū)域內(nèi)存耗盡了,報(bào)錯(cuò)了

內(nèi)存泄漏:垃圾回收器無(wú)法回收某部分內(nèi)存,這種現(xiàn)象就叫做內(nèi)存泄漏;

上圖中5塊內(nèi)存區(qū)域,除了程序計(jì)數(shù)器,都會(huì)產(chǎn)生內(nèi)存溢出

  • 不會(huì)出現(xiàn)內(nèi)存溢出的區(qū)域 – 程序計(jì)數(shù)器
  • 出現(xiàn) OutOfMemoryError 的情況
    • 堆內(nèi)存耗盡 – 對(duì)象越來(lái)越多,又一直在使用,不能被垃圾回收
    • 方法區(qū)內(nèi)存耗盡 – 加載的類越來(lái)越多,很多框架都會(huì)在運(yùn)行期間動(dòng)態(tài)產(chǎn)生新的類
    • 虛擬機(jī)棧累積 – 每個(gè)線程最多會(huì)占用 1 M 內(nèi)存,線程個(gè)數(shù)越來(lái)越多,而又長(zhǎng)時(shí)間運(yùn)行不銷毀時(shí)
  • 出現(xiàn) StackOverflowError 的區(qū)域
    • JVM 虛擬機(jī)棧,原因有方法遞歸調(diào)用未正確結(jié)束、反序列化 json 時(shí)循環(huán)引用 (線程內(nèi)方法不斷調(diào)用,而每個(gè)線程內(nèi)的1M內(nèi)存消耗掉,就會(huì)報(bào)StackOverflowError)

方法區(qū)、永久代、元空間

  • 方法區(qū)是 JVM 規(guī)范中定義的一塊內(nèi)存區(qū)域,用來(lái)存儲(chǔ)類元數(shù)據(jù)、方法字節(jié)碼即時(shí)編譯器需要的信息等
  • 永久代是 Hotspot 虛擬機(jī)對(duì) JVM 規(guī)范的實(shí)現(xiàn)(1.8 之前)
  • 元空間是 Hotspot 虛擬機(jī)對(duì) JVM 規(guī)范的另一種實(shí)現(xiàn)(1.8 以后),使用本地內(nèi)存作為這些信息的存儲(chǔ)空間

方法區(qū)只是 JVM 規(guī)范中的一種定義 (你得有,怎么實(shí)現(xiàn)我不管)
永久代和元空間才是對(duì)規(guī)范的物理實(shí)現(xiàn)

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

從這張圖學(xué)到三點(diǎn)

類元數(shù)據(jù): 描述類的數(shù)據(jù) (哪些成員,什么類型,長(zhǎng)度多少…) 存儲(chǔ)在元空間(方法區(qū)的物理實(shí)現(xiàn))
類名.class 字節(jié)碼對(duì)象,既然是對(duì)象,自然就存儲(chǔ)在堆中了
類的原始信息(類元數(shù)據(jù))存儲(chǔ)在元空間中,無(wú)法直接訪問(wèn),得通過(guò)java對(duì)象訪問(wèn),這個(gè)對(duì)象就是字節(jié)碼對(duì)象

  • 當(dāng)?shù)谝淮斡玫侥硞€(gè)類時(shí),由類加載器將 class 文件的類元信息讀入,并存儲(chǔ)于元空間
  • X,Y 的類元信息是存儲(chǔ)于元空間中,無(wú)法直接訪問(wèn)
  • 可以用 X.class,Y.class 間接訪問(wèn)類元信息,它們倆屬于 java 對(duì)象 (字節(jié)碼對(duì)象),我們的代碼中可以使用

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

從這張圖可以學(xué)到

  • 堆內(nèi)存中:當(dāng)一個(gè)類加載器對(duì)象,這個(gè)類加載器對(duì)象加載的所有類對(duì)象,這些類對(duì)象對(duì)應(yīng)的所有實(shí)例對(duì)象都沒人引用時(shí),GC 時(shí)就會(huì)對(duì)它們占用的堆內(nèi)存進(jìn)行釋放
  • 元空間中:內(nèi)存釋放以類加載器為單位,當(dāng)堆中類加載器內(nèi)存釋放時(shí),對(duì)應(yīng)的元空間中的類元信息也會(huì)釋放

一般系統(tǒng)類加載器不會(huì)被釋放,我們自定義的類加載器不再使用時(shí)會(huì)被釋放( 釋放啥? 元空間內(nèi)存啊 )

2. JVM 內(nèi)存參數(shù)

要求

  • 熟悉常見的 JVM 參數(shù),尤其和大小相關(guān)的

提問(wèn): java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

堆內(nèi)存,按大小設(shè)置

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

解釋:

  • -Xms JVM最小內(nèi)存(包括新生代和老年代)
  • -Xmx JVM最大內(nèi)存(包括新生代和老年代)
  • 通常建議將 -Xms 與 -Xmx 設(shè)置為大小相等,即不需要保留內(nèi)存,不需要從小到大增長(zhǎng),這樣性能較好
  • -XX:NewSize 與 -XX:MaxNewSize 設(shè)置新生代的最小與最大值,但一般不建議設(shè)置,由 JVM 自己控制
  • -Xmn 設(shè)置新生代大小,相當(dāng)于同時(shí)設(shè)置了 -XX:NewSize 與 -XX:MaxNewSize 并且取值相等
  • 保留是指,一開始不會(huì)占用那么多內(nèi)存,隨著使用內(nèi)存越來(lái)越多,會(huì)逐步使用這部分保留內(nèi)存。下同

從年代角度,JVM將內(nèi)存劃分為新生代和老年代
-Xmn的n就是new 新生代

堆內(nèi)存,按比例設(shè)置

下圖的 new 就是新生代,新生代內(nèi)存可以進(jìn)一步劃分為eden和Survivor,Survivor又可以細(xì)分為:from,to
old 自然就是老年代內(nèi)存

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

解釋:

  • -XX:NewRatio=2:1 表示老年代占兩份,新生代占一份
  • -XX:SurvivorRatio=4:1 表示新生代分成六份,伊甸園占四份,from 和 to 各占一份
  • (注意1:默認(rèn)8:1 也就是8:1:1) (注意2:上面的4:1指的是eden:from=eden:to=4:1 因?yàn)閒rom和to總是相等的)

元空間內(nèi)存設(shè)置

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

解釋:

  • class space 存儲(chǔ)類的基本信息,最大值受 -XX:CompressedClassSpaceSize 控制
  • non-class space 存儲(chǔ)除類的基本信息以外的其它信息(如方法字節(jié)碼、注解等)
  • class space 和 non-class space 總大小受 -XX:MaxMetaspaceSize 控制

注意:

  • 這里 -XX:CompressedClassSpaceSize 這段空間還與是否開啟了指針壓縮有關(guān),這里暫不深入展開,可以簡(jiǎn)單認(rèn)為指針壓縮默認(rèn)開啟

代碼緩存內(nèi)存設(shè)置

JIT即時(shí)編譯器,將熱點(diǎn)代碼編譯成機(jī)器碼后緩存起來(lái),就存放在CodeCache 代碼緩存區(qū)

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

解釋:

  • 如果 -XX:ReservedCodeCacheSize < 240m,所有優(yōu)化機(jī)器代碼不加區(qū)分存在一起
  • 否則,分成三個(gè)區(qū)域(優(yōu)化代碼細(xì)分3份)(圖中筆誤 mthod 拼寫錯(cuò)誤,少一個(gè) e)
    • non-nmethods - JVM 自己用的代碼 (JIT編譯器自己的代碼)
    • profiled nmethods - 部分優(yōu)化的機(jī)器碼
    • non-profiled nmethods - 完全優(yōu)化的機(jī)器碼

線程內(nèi)存設(shè)置

也就是JVM虛擬機(jī)棧的內(nèi)存
-Xss 設(shè)置每個(gè)線程占用的內(nèi)存
不設(shè)置,linux系統(tǒng)默認(rèn)1MB, 也就是每個(gè)線程默認(rèn)占用1MB內(nèi)存

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

官方參考文檔

  • https://docs.oracle.com/en/java/javase/11/tools/java.html#GUID-3B1CE181-CD30-4178-9602-230B800D4FAE

3. JVM 垃圾回收

要求

  • 掌握垃圾回收算法
  • 掌握分代回收思想
  • 理解三色標(biāo)記及漏標(biāo)處理
  • 了解常見垃圾回收器

eg: 內(nèi)存中一些對(duì)象,已經(jīng)沒有任何內(nèi)存中引用指向它,GC就可以將它回收了

三種垃圾回收算法

標(biāo)記清除法

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

解釋:

  1. 找到 GC Root 對(duì)象,即那些一定不會(huì)被回收的對(duì)象,如正執(zhí)行方法內(nèi)局部變量引用的對(duì)象、靜態(tài)變量引用的對(duì)象
  2. 標(biāo)記階段:沿著 GC Root 對(duì)象的引用鏈找,直接或間接引用到的對(duì)象加上標(biāo)記
  3. 清除階段:釋放未加標(biāo)記的對(duì)象占用的內(nèi)存

局部變量正在引用或者說(shuō)使用的對(duì)象一定不能回收,可以作為根對(duì)象
靜態(tài)變量得一直存在,不能被回收,可以作為根對(duì)象

要點(diǎn):

  • 標(biāo)記速度與存活對(duì)象線性關(guān)系
  • 清除速度與內(nèi)存大小線性關(guān)系
  • 缺點(diǎn)是會(huì)產(chǎn)生內(nèi)存碎片 (未標(biāo)記的內(nèi)存極大概率都是不連續(xù)的,會(huì)產(chǎn)生大量?jī)?nèi)存碎片 所以基本上已經(jīng)被棄用了)

標(biāo)記整理法

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

解釋:

  1. 前面的標(biāo)記階段、清理階段與標(biāo)記清除法類似
  2. 多了一步整理的動(dòng)作,將存活對(duì)象向一端移動(dòng),可以避免內(nèi)存碎片產(chǎn)生

特點(diǎn):

  • 標(biāo)記速度與存活對(duì)象線性關(guān)系

  • 清除與整理速度與內(nèi)存大小成線性關(guān)系

  • 缺點(diǎn)是性能上較慢

標(biāo)記復(fù)制法

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

解釋:

  1. 將整個(gè)內(nèi)存分成兩個(gè)大小相等的區(qū)域,from 和 to,其中 to 總是處于空閑,from 存儲(chǔ)新創(chuàng)建的對(duì)象
  2. 標(biāo)記階段與前面的算法類似
  3. 在找出存活對(duì)象后,會(huì)將它們從 from 復(fù)制到 to 區(qū)域,復(fù)制的過(guò)程中自然完成了碎片整理(復(fù)制完后from區(qū)全部都可以清除了)
  4. 復(fù)制完成后,交換 from 和 to 的位置即可 (兩個(gè)區(qū)域交替使用,永遠(yuǎn)不會(huì)產(chǎn)生內(nèi)存碎片問(wèn)題,多好啊)

特點(diǎn):

  • 標(biāo)記與復(fù)制速度與存活對(duì)象成線性關(guān)系
  • 缺點(diǎn)是會(huì)占用成倍的空間

GC 與分代回收算法

GC 的目的在于實(shí)現(xiàn)無(wú)用對(duì)象內(nèi)存自動(dòng)釋放,減少內(nèi)存碎片、加快分配速度

GC 要點(diǎn):

  • 回收區(qū)域是堆內(nèi)存,不包括虛擬機(jī)棧 (方法棧中內(nèi)存,在方法調(diào)用結(jié)束會(huì)自動(dòng)釋放方法占用內(nèi)存)
  • 判斷無(wú)用對(duì)象,使用可達(dá)性分析算法三色標(biāo)記法標(biāo)記存活對(duì)象,回收未標(biāo)記對(duì)象
  • GC 具體的實(shí)現(xiàn)稱為垃圾回收器
  • GC 大都采用了分代回收思想
    • 理論依據(jù)是大部分對(duì)象朝生夕滅,用完立刻就可以回收,另有少部分對(duì)象會(huì)長(zhǎng)時(shí)間存活,每次很難回收
    • 根據(jù)這兩類對(duì)象的特性將回收區(qū)域分為新生代老年代,新生代采用標(biāo)記復(fù)制法老年代一般采用標(biāo)記整理法
  • 根據(jù) GC 的規(guī)??梢苑殖?Minor GC,Mixed GC,Full GC

新生代:垃圾對(duì)象比較多 (方法內(nèi)經(jīng)常new的局部對(duì)象)
老年代: 存活對(duì)象比較多,很難回收,或者說(shuō)不需要經(jīng)常回收,整理也不會(huì)特別耗時(shí) (eg: 靜態(tài)對(duì)象,框架里面長(zhǎng)期使用的對(duì)象) (老年代存活對(duì)象多,標(biāo)記復(fù)制法也會(huì)極其浪費(fèi)內(nèi)存)
可達(dá)性分析算法:找到GC Root 打上標(biāo)記 (先找到一定不會(huì)被回收的對(duì)象,然后沿著其引用鏈再找,再標(biāo)記)
三色標(biāo)記法:見下文
垃圾回收器有很多種,見下文
.
Minor GC:新生代的垃圾回收,小范圍垃圾回收,暫停時(shí)間短,對(duì)系統(tǒng)影響小
Full GC: 新生代和老年代都發(fā)生內(nèi)存不足了,來(lái)了一次全面的垃圾回收,暫停時(shí)間長(zhǎng),明顯感到系統(tǒng)卡頓,一般是不愿意看到Full GC的
Mixed GC: 位于以上二者之間,指的是:新生代發(fā)生了垃圾回收,部分的老年代也發(fā)生了垃圾回收,一種混合垃圾回收,G1垃圾回收器獨(dú)有的回收方式

個(gè)人再整理一下GC和堆內(nèi)存相關(guān)概念:
GC只是回收堆內(nèi)存
new出來(lái)的對(duì)象,都放在堆內(nèi)存
堆內(nèi)存劃分:
從年代角度,JVM將堆內(nèi)存劃分為新生代和老年代
新生代內(nèi)存又可以分為: eden和Survivor,Survivor又可以細(xì)分為:from,to
先總覽一下,有個(gè)大致框架: 再慢慢看下面詳細(xì)過(guò)程
java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize
圖中黃色空閑,白色是已分配
打標(biāo)記可以用一句話概括: 尋找有沒有被根對(duì)象直接或者間接引用到的

分代回收

  1. 伊甸園 eden,最初對(duì)象都分配到這里,與幸存區(qū) survivor(分成 from 和 to)合稱新生代,

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 當(dāng)伊甸園內(nèi)存不足,標(biāo)記伊甸園與 from(現(xiàn)階段沒有)的存活對(duì)象

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 將存活對(duì)象采用復(fù)制算法復(fù)制到 to 中,復(fù)制完畢后,伊甸園和 from 內(nèi)存都得到釋放

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 將 from 和 to 交換位置

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 經(jīng)過(guò)一段時(shí)間后伊甸園的內(nèi)存又出現(xiàn)不足

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 標(biāo)記伊甸園與 from(現(xiàn)階段沒有)的存活對(duì)象

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 將存活對(duì)象采用復(fù)制算法復(fù)制到 to 中

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 復(fù)制完畢后,伊甸園和 from 內(nèi)存都得到釋放

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 將 from 和 to 交換位置

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 老年代 old,當(dāng)幸存區(qū)對(duì)象熬過(guò)幾次回收(最多15次),晉升到老年代(幸存區(qū)內(nèi)存不足或大對(duì)象會(huì)導(dǎo)致提前晉升

幸存區(qū)不足: to不夠復(fù)制的,肯定把已經(jīng)在to的給移到老年代 (to很大的,不足肯定是有之前熬過(guò)了回收的對(duì)象存在的) 提前競(jìng)升也是沒有辦法的事情
大對(duì)象:每次GC都要復(fù)制來(lái)復(fù)制去的,太消耗了,不如提前競(jìng)升為老年代

GC 規(guī)模

  • Minor GC 發(fā)生在新生代的垃圾回收,暫停時(shí)間短

  • Mixed GC 新生代 + 老年代部分區(qū)域的垃圾回收,G1 收集器特有

  • Full GC 新生代 + 老年代 完整(全面) 垃圾回收,暫停時(shí)間長(zhǎng),應(yīng)盡力避免

三色標(biāo)記

即用三種顏色記錄對(duì)象的標(biāo)記狀態(tài)

  • 黑色 – 已標(biāo)記
  • 灰色 – 標(biāo)記中
  • 白色 – 還未標(biāo)記

黑色 – 已標(biāo)記: 沿著根對(duì)象的引用鏈,已經(jīng)找到這個(gè)對(duì)象了,且此對(duì)象內(nèi)部的其他引用也已經(jīng)處理完成了
灰色 – 標(biāo)記中:沿著根對(duì)象的引用鏈,已經(jīng)找到這個(gè)對(duì)象了,但這個(gè)對(duì)象內(nèi)部的其他引用還沒有處理完
白色 – 還未標(biāo)記: 就是標(biāo)記完最終剩下的對(duì)象了

  1. 起始的三個(gè)對(duì)象還未處理完成,用灰色表示

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 該對(duì)象的引用已經(jīng)處理完成,用黑色表示,黑色引用的對(duì)象變?yōu)榛疑?/li>

將其直接引用標(biāo)記為灰色,就認(rèn)為他的引用處理完成了,就可以直接標(biāo)記為黑色了

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 依次類推

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 沿著引用鏈都標(biāo)記了一遍

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 最后未標(biāo)記的白色對(duì)象,即為垃圾

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

并發(fā)漏標(biāo)問(wèn)題

前面的GC是非并發(fā)的,GC在工作時(shí),用戶線程就暫停了,因此用戶線程不會(huì)對(duì)GC線程造成影響
也即GC在打標(biāo)記時(shí),用戶線程暫停了,不會(huì)對(duì)打標(biāo)記產(chǎn)生任何影響(不會(huì)修改引用鏈)
非并發(fā)GC效率低,并發(fā)GC,也即并發(fā)標(biāo)記,肯定是需要的
那么GC在打標(biāo)記時(shí),用戶線程還在工作,萬(wàn)一打標(biāo)過(guò)程中,用戶線程修改了引用關(guān)系,很容易導(dǎo)致漏標(biāo)啊

比較先進(jìn)的垃圾回收器都支持并發(fā)標(biāo)記,即在標(biāo)記過(guò)程中,用戶線程仍然能工作。但這樣帶來(lái)一個(gè)新的問(wèn)題,如果用戶線程修改了對(duì)象引用,那么就存在漏標(biāo)問(wèn)題。例如:

  1. 如圖所示標(biāo)記工作尚未完成

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 用戶線程同時(shí)在工作,斷開了第一層 3、4 兩個(gè)對(duì)象之間的引用,這時(shí)對(duì)于正在處理 3 號(hào)對(duì)象的垃圾回收線程來(lái)講,它會(huì)將 4 號(hào)對(duì)象當(dāng)做是白色垃圾

這個(gè)時(shí)候回收3其實(shí)也是合理的
但是萬(wàn)一他斷開后又被別的對(duì)象引用了呢(不是我們不用了,而是我給別人用了) 就不能回收了呀(見下)

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 但如果其他用戶線程又建立了 2、4 兩個(gè)對(duì)象的引用,這時(shí)因?yàn)?2 號(hào)對(duì)象是黑色已處理對(duì)象了,因此垃圾回收線程不會(huì)察覺到這個(gè)引用關(guān)系的變化從而產(chǎn)生了漏標(biāo)

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 如果用戶線程讓黑色對(duì)象引用了一個(gè)新增對(duì)象,一樣會(huì)存在漏標(biāo)問(wèn)題

黑色對(duì)象已經(jīng)處理過(guò)了(被標(biāo)記為黑色的,會(huì)認(rèn)為已經(jīng)處理過(guò)了),已經(jīng)處理過(guò)的對(duì)象,不會(huì)再去處理他的(不會(huì)再重復(fù)地找他的直接引用然后標(biāo)記為灰色)

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

因此對(duì)于并發(fā)標(biāo)記而言,必須解決漏標(biāo)問(wèn)題,也就是要記錄標(biāo)記過(guò)程中的變化。有兩種解決方法:

解決漏標(biāo),核心就是:記錄標(biāo)記過(guò)程中的變化+二次處理

  1. Incremental Update 增量更新法,CMS 垃圾回收器采用
    • 思路是攔截每次賦值動(dòng)作,只要賦值發(fā)生,被賦值的對(duì)象就會(huì)被記錄下來(lái),在重新標(biāo)記階段再確認(rèn)一遍
  2. Snapshot At The Beginning,SATB 原始快照法,G1 垃圾回收器采用
    • 思路也是攔截每次賦值動(dòng)作,不過(guò)記錄的對(duì)象不同,也需要在重新標(biāo)記階段對(duì)這些對(duì)象二次處理
    • 新加對(duì)象會(huì)被記錄
    • 被刪除引用關(guān)系的對(duì)象也被記錄

上圖紅箭頭 黑->白 黑色對(duì)象就是被賦值對(duì)象(把白色對(duì)象賦值給黑色對(duì)象)

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

垃圾回收器 - Parallel GC

  • eden 內(nèi)存不足發(fā)生 Minor GC,采用標(biāo)記復(fù)制算法,需要暫停用戶線程

  • old 內(nèi)存不足發(fā)生 Full GC,采用標(biāo)記整理算法,需要暫停用戶線程

  • 注重吞吐量 (響應(yīng)時(shí)間、暫停時(shí)間慢點(diǎn)沒關(guān)系,但是總體上暫停時(shí)間短一點(diǎn)就ok了)

Parallel GC: 實(shí)際上由2個(gè)垃圾回收器組成,一個(gè)工作在新生代,一個(gè)工作在老年代
Minor GC 僅僅新生代垃圾回收器工作
Full GC 時(shí),新生代和老年代垃圾回收器都會(huì)工作
標(biāo)記復(fù)制和標(biāo)記整理(慢)都不會(huì)有內(nèi)存碎片

垃圾回收器 - ConcurrentMarkSweep GC

  • 它是工作在 old 老年代,支持并發(fā)標(biāo)記的一款回收器,采用并發(fā)清除算法

    • 并發(fā)標(biāo)記時(shí)不需暫停用戶線程 (可能導(dǎo)致漏標(biāo))
    • 重新標(biāo)記時(shí)仍需暫停用戶線程 (處理漏標(biāo)時(shí)用戶線程不能再并發(fā)了,得暫停,否則沒完沒了了)
  • 如果并發(fā)失敗(即回收速度趕不上創(chuàng)建新對(duì)象速度),會(huì)觸發(fā) Full GC

  • 注重響應(yīng)時(shí)間 (也就這一個(gè)好處 響應(yīng)時(shí)間很快 不需要等很久)

ConcurrentMarkSweep GC 這是一個(gè)老年代垃圾回收器,
ConcurrentMarkSweep GC 簡(jiǎn)稱 CMS垃圾回收器
Concurrent:并發(fā) Mark:標(biāo)記 Sweep: 掃描,打掃
并發(fā)就意味著GC時(shí)用戶線程暫停時(shí)間很短,可以并發(fā)執(zhí)行嘛
標(biāo)記指的是標(biāo)記為黑、灰、白三色,清除指的是清除回收白色垃圾對(duì)象
然而正因?yàn)槿思也捎玫氖?標(biāo)記清除法,有內(nèi)存碎片問(wèn)題,因此最新的JDK已經(jīng)將其標(biāo)記為廢棄了

STW(Stop The World)
java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

垃圾回收器 - G1 GC

  • 響應(yīng)時(shí)間與吞吐量兼顧
  • 劃分成多個(gè)區(qū)域,每個(gè)區(qū)域都可以充當(dāng) eden,survivor,old, humongous,其中 humongous 專為大對(duì)象準(zhǔn)備
  • 分成三個(gè)階段:新生代回收、并發(fā)標(biāo)記、混合收集
  • 如果并發(fā)失?。椿厥账俣融s不上創(chuàng)建新對(duì)象速度),會(huì)觸發(fā) Full GC

G1 GC 讀作:G one 垃圾回收器
humongous: 巨大無(wú)比的

總覽:
java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

G1也有保底策略:回收速度<新對(duì)象創(chuàng)建速度 也就是并發(fā)失敗 : FailBack Full GC 整體進(jìn)行一次回收,暫停時(shí)間會(huì)比較長(zhǎng)

G1 回收階段 - 新生代回收

  1. 初始時(shí),所有區(qū)域都處于空閑狀態(tài)

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 創(chuàng)建了一些對(duì)象,挑出一些空閑區(qū)域作為伊甸園區(qū)存儲(chǔ)這些對(duì)象

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 當(dāng)伊甸園需要垃圾回收時(shí),挑出一個(gè)空閑區(qū)域作為幸存區(qū),用復(fù)制算法復(fù)制存活對(duì)象,需要暫停用戶線程
    (新生代采用標(biāo)記復(fù)制法,復(fù)制時(shí)要STW, 非并發(fā)的)
    (eden區(qū)所有存活對(duì)象復(fù)制到一個(gè)幸存區(qū)(to區(qū) 然后to和from區(qū)互換地位 ))

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 復(fù)制完成,將之前的伊甸園內(nèi)存釋放

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 隨著時(shí)間流逝,伊甸園的內(nèi)存又有不足

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 將伊甸園以及之前幸存區(qū)中的存活對(duì)象,采用復(fù)制算法,復(fù)制到新的幸存區(qū),其中較老對(duì)象晉升至老年代

(eden區(qū)和幸存from區(qū)中的對(duì)象全部復(fù)制到新的幸存區(qū)(類似to))

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 釋放伊甸園以及之前幸存區(qū)的內(nèi)存

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

G1 回收階段 - 并發(fā)標(biāo)記與混合收集

前提,老年代內(nèi)存快不足了,才需要開始回收老年代,老年代標(biāo)記策略是:并發(fā)標(biāo)記

  1. 當(dāng)老年代占用內(nèi)存超過(guò)閾值后,觸發(fā)并發(fā)標(biāo)記,這時(shí)無(wú)需暫停用戶線程

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

也不是直接回收所有的老年代區(qū)域,而是挑選幾個(gè)回收價(jià)值高的老年代區(qū)域(存活對(duì)象很少)先進(jìn)行回收

  1. 并發(fā)標(biāo)記之后,會(huì)有重新標(biāo)記階段解決漏標(biāo)問(wèn)題,此時(shí)需要暫停用戶線程。這些都完成后就知道了老年代有哪些存活對(duì)象,隨后進(jìn)入混合收集階段。此時(shí)不會(huì)對(duì)所有老年代區(qū)域進(jìn)行回收,而是根據(jù)暫停時(shí)間目標(biāo)優(yōu)先回收價(jià)值高(存活對(duì)象少)的區(qū)域(這也是 Gabage First 名稱的由來(lái))。

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

混合收集,不僅收集挑選出來(lái)的回收價(jià)值高的老年代(上圖紅色),還收集新生代(eden+survivor)

  1. 混合收集階段中,參與復(fù)制的有 eden、survivor、old,下圖顯示了伊甸園和幸存區(qū)的存活對(duì)象復(fù)制

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 下圖顯示了老年代和幸存區(qū)晉升的存活對(duì)象的復(fù)制

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 復(fù)制完成,內(nèi)存得到釋放。進(jìn)入下一輪的新生代回收、并發(fā)標(biāo)記、混合收集

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

4. 內(nèi)存溢出

內(nèi)存溢出: 該區(qū)域內(nèi)存耗盡了,報(bào)錯(cuò)了

要求

  • 能夠說(shuō)出幾種典型的導(dǎo)致內(nèi)存溢出的情況

典型情況

  • 1)誤用線程池導(dǎo)致的內(nèi)存溢出
    • 參考 day03.TestOomThreadPool
      java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize
      LinkedBlockingQueue就是一種無(wú)界隊(duì)列 (Interger類型不溢出,他就不會(huì)溢出)

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize
上圖代碼不斷創(chuàng)建新的現(xiàn)場(chǎng)并提交,由于每個(gè)線程都要阻塞30ms,阻塞隊(duì)列越來(lái)越大,無(wú)限制增長(zhǎng),就會(huì)導(dǎo)致內(nèi)存爆

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize
java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  • 2)查詢數(shù)據(jù)量太大導(dǎo)致的內(nèi)存溢出
    • 參考 day03.TestOomTooManyObject

數(shù)據(jù)庫(kù)條目太多了,你findAll, 一次查可能就100w條,就是100w個(gè)很普通的Product商品POJO集合,也要占用363MB的內(nèi)存, 服務(wù)器內(nèi)存再大,也經(jīng)不起這么造啊, 10個(gè)用戶就得占用3G內(nèi)存呀
所以后端開發(fā)千萬(wàn)不要findAll( 自己不要寫,也不要調(diào)用)
以后寫代碼,sql查詢一定要加limit (光有條件都不行,條件可能失效啊)

這些錯(cuò)誤在測(cè)試環(huán)境下是測(cè)不出來(lái)的,生產(chǎn)環(huán)境下才有百萬(wàn)級(jí)別的數(shù)據(jù),才會(huì)暴露出來(lái)的問(wèn)題

所以項(xiàng)目做完后,做一下壓力測(cè)試也是很有必要的,面試會(huì)問(wèn)到

  • 3)動(dòng)態(tài)生成類導(dǎo)致的內(nèi)存溢出
    • 參考 day03.TestOomTooManyClass
      java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize
      java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

5. 類加載

要求

  • 掌握類加載階段
  • 掌握類加載器
  • 理解雙親委派機(jī)制

類加載過(guò)程的三個(gè)階段

  1. 加載

    1. 將類的字節(jié)碼載入方法區(qū),并創(chuàng)建類.class 對(duì)象
    2. 如果此類的父類沒有加載,先加載父類
    3. 加載是懶惰執(zhí)行 (真的用到此類時(shí)才加載)

類.class對(duì)象里面有一系列反射方法,可以獲知類的所有信息:有哪些成員,有哪些方法
類.class對(duì)象存放在堆里面

  1. 鏈接

    1. 驗(yàn)證 – 驗(yàn)證類是否符合 Class 規(guī)范,合法性、安全性檢查
    2. 準(zhǔn)備 – 為 static 變量分配空間,設(shè)置默認(rèn)值 (但是手動(dòng)寫了賦值語(yǔ)句此時(shí)是不會(huì)執(zhí)行的,會(huì)在初始化階段執(zhí)行,這里其實(shí)只是給靜態(tài)變量分配空間 (final變量是例外,會(huì)在此時(shí)賦值))
    3. 解析 – 將常量池的符號(hào)引用解析為直接引用
  2. 初始化

    1. 靜態(tài)代碼塊、static 修飾的變量賦值、static final 修飾的引用類型變量賦值,會(huì)被合并成一個(gè) <cinit> 方法,在初始化時(shí)被調(diào)用
    2. static final 修飾的基本類型變量賦值,在鏈接階段就已完成
    3. 初始化是懶惰執(zhí)行 (真正要用到該類時(shí)才會(huì)初始化 懶惰執(zhí)行,化整為零,多好)

驗(yàn)證手段

  • 使用 jps 查看進(jìn)程號(hào)
  • 使用 jhsdb 調(diào)試,執(zhí)行命令 jhsdb.exe hsdb 打開它的圖形界面
    • Class Browser 可以查看當(dāng)前 jvm 中加載了哪些類
    • 控制臺(tái)的 universe 命令查看堆內(nèi)存范圍
    • 控制臺(tái)的 g1regiondetails 命令查看 region 詳情
    • scanoops 起始地址 結(jié)束地址 對(duì)象類型 可以根據(jù)類型查找某個(gè)區(qū)間內(nèi)的對(duì)象地址
    • 控制臺(tái)的 inspect 地址 指令能夠查看這個(gè)地址對(duì)應(yīng)的對(duì)象詳情
  • 使用 javap 命令可以查看 class 字節(jié)碼

代碼說(shuō)明

  • day03.loader.TestLazy - 驗(yàn)證類的加載是懶惰的,用到時(shí)才觸發(fā)類加載
  • day03.loader.TestFinal - 驗(yàn)證使用 final 修飾的變量不會(huì)觸發(fā)類加載

字節(jié)碼對(duì)象確實(shí)在堆空間(eden區(qū)域),不在方法區(qū)

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize
java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize
java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  • 初始化方法(靜態(tài)成員(非final普通類型)和靜態(tài)代碼塊)

會(huì)將靜態(tài)成員和靜態(tài)代碼快里的語(yǔ)句,整合在一起,變成一個(gè)方法(cinit方法),在類初始化時(shí)調(diào)用這個(gè)方法
注意:final static 非引用類型 的變量在類加載時(shí)(創(chuàng)建字節(jié)碼對(duì)象時(shí))就會(huì)初始化好的,這里不需要整合了

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  • 使用 final 修飾的非引用類型變量不會(huì)觸發(fā)類加載

前兩個(gè)打印語(yǔ)句,看起來(lái)使用了類,Student.c和Student.m 實(shí)際上并沒有真正使用到類,因此此時(shí)類并沒有被加載,內(nèi)存中并沒有類,充分證明了類的加載是懶加載
此時(shí)類加載完成了,可以看到類的字節(jié)碼信息了(類的結(jié)構(gòu):哪些成員、哪些方法)

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize
當(dāng)一個(gè)類A使用另一個(gè)類B的final static 普通類型 變量,實(shí)際上是常量,這個(gè)時(shí)候類A直接將該類B常量復(fù)制一份到自己類中,根本不會(huì)真的用到另一個(gè)類B

如果常量數(shù)值比較小,那么直接就寫死在方法里
如果數(shù)值比較大,超過(guò)了short的最大范圍(>32767) 就會(huì)放到常量池子中,需要用到時(shí)到常量池中拿就好了
也即是: 數(shù)值較大,會(huì)復(fù)制到類A自己的常量池中,每個(gè)類都有自己的常量池(一個(gè)常量列表,且1,2,3,… 地給每個(gè)常量編好了號(hào),給出編號(hào),直接到常量池中取那個(gè)常量的值)

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

解析:符號(hào)引用-》直接引用 隨著代碼的執(zhí)行不斷進(jìn)行的過(guò)程,不是一次性就能完成的
類的static成員變量的引用,都是放在常量池的
沒有給靜態(tài)成員賦值時(shí),常量池中就沒有直接引用,只有符號(hào)引用(空指針 只知道要指向什么類型,但是并沒有真的內(nèi)存)

jdk 8 的類加載器

名稱 加載哪的類 說(shuō)明
Bootstrap ClassLoader JAVA_HOME/jre/lib 無(wú)法直接訪問(wèn)
Extension ClassLoader JAVA_HOME/jre/lib/ext 上級(jí)為 Bootstrap,顯示為 null
Application ClassLoader classpath 上級(jí)為 Extension
自定義類加載器 自定義 上級(jí)為 Application

像String.class, Application和Extension類加載器中都沒有,無(wú)法加載,這個(gè)時(shí)候必須向上詢問(wèn)Bootstrap啟動(dòng)類加載器,讓他加載,然后下級(jí)都可見 (String類型是jdk的,上層都需要用到,所有都可見也是合理的)
像自己寫的類Student.class, 也會(huì)遵循規(guī)則先逐級(jí)向上詢問(wèn),上層加載器都沒有這個(gè)類,Application類加載器才有了加載Student.class的資格,進(jìn)行加載(上層類加載器不可見,也不需要可見,這種屏蔽很合理)

雙親委派機(jī)制

所謂的雙親委派,就是指優(yōu)先委派上級(jí)類加載器進(jìn)行加載,如果上級(jí)類加載器

  • 能找到這個(gè)類,由上級(jí)加載,加載后該類也對(duì)下級(jí)加載器可見
  • 找不到這個(gè)類,則下級(jí)類加載器才有資格執(zhí)行加載

雙親委派的目的有兩點(diǎn)

  1. 讓上級(jí)類加載器中的類對(duì)下級(jí)共享(反之不行),即能讓你的類能依賴到 jdk 提供的核心類 (反之不行:jdk肯定不需要依賴你自己寫的類)

  2. 讓類的加載有優(yōu)先次序,保證核心類優(yōu)先加載

上級(jí)類加載器中的類對(duì)下級(jí)可見
但是下級(jí)類加載器中的類對(duì)上級(jí)不可見

對(duì)雙親委派的誤解

下面面試題的回答是錯(cuò)誤的

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

錯(cuò)在哪了?

  • 自己編寫類加載器就能加載一個(gè)假冒的 java.lang.System 嗎? 答案是不行。

  • 假設(shè)你自己的類加載器用了雙親委派,那么優(yōu)先由啟動(dòng)類加載器加載真正的 java.lang.System,自然不會(huì)加載假冒的

  • 假設(shè)你自己的類加載器不用雙親委派,那么你的類加載器加載假冒的 java.lang.System 時(shí),它需要先加載父類 java.lang.Object,而你沒有用委派,找不到 java.lang.Object 所以加載會(huì)失敗

  • 以上也僅僅是假設(shè)。事實(shí)上操作你就會(huì)發(fā)現(xiàn),自定義類加載器加載以 java. 打頭的類時(shí),會(huì)拋安全異常,在 jdk9 以上版本這些特殊包名都與模塊進(jìn)行了綁定,更連編譯都過(guò)不了 (實(shí)際操作,直接拋安全異常,或者編譯不過(guò),到不了假設(shè)那一步,jdk已經(jīng)做了安全措施,防止你這么做了, 直接就不允許你重復(fù)寫java.lang這重包名了)

代碼說(shuō)明

  • day03.loader.TestJdk9ClassLoader - 演示類加載器與模塊的綁定關(guān)系 =》 結(jié)論:不準(zhǔn)自己重復(fù)寫jdk已經(jīng)有的包名.類名

6. 四種引用

要求

  • 掌握四種引用

強(qiáng)引用

  1. 普通變量賦值即為強(qiáng)引用,如 A a = new A();

  2. 通過(guò) GC Root 的引用鏈,如果強(qiáng)引用不到該對(duì)象,該對(duì)象才能被回收

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

軟引用(SoftReference)

  1. 例如:SoftReference a = new SoftReference(new A()); (中間有一個(gè)SoftReference對(duì)象做中轉(zhuǎn),a間接關(guān)聯(lián)到對(duì)象new A())

  2. 如果僅有軟引用該對(duì)象時(shí),首次垃圾回收不會(huì)回收該對(duì)象,如果內(nèi)存仍不足,再次回收時(shí)才會(huì)釋放對(duì)象 (內(nèi)存不足時(shí)會(huì)觸發(fā)GC,第一次饒過(guò)你,第二次內(nèi)存不足又觸發(fā)了GC, 是會(huì)將軟引用對(duì)象回收的(有強(qiáng)引用指向的對(duì)象GC無(wú)法回收))

  3. 軟引用自身需要配合引用隊(duì)列來(lái)釋放(如下圖,a對(duì)象是軟引用,但是SoftReference自身還是強(qiáng)引用,GC無(wú)法回收軟引用自身)

  4. 典型例子是反射數(shù)據(jù)(通過(guò)反射獲取的數(shù)據(jù)都是軟引用數(shù)據(jù),如:類名.class=》獲取的成員變量,方法等數(shù)據(jù)信息都是軟引用)

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

弱引用(WeakReference)

  1. 例如:WeakReference a = new WeakReference(new A());

  2. 如果僅有弱引用引用該對(duì)象時(shí),只要發(fā)生垃圾回收,就會(huì)釋放該對(duì)象

  3. 弱引用自身需要配合引用隊(duì)列來(lái)釋放 (同上)

  4. 典型例子是 ThreadLocalMap 中的 Entry 對(duì)象

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

虛引用(PhantomReference)

  1. 例如: PhantomReference a = new PhantomReference(new A(), referenceQueue);

  2. 必須配合引用隊(duì)列一起使用,當(dāng)虛引用所引用的對(duì)象被回收時(shí),由 Reference Handler 線程將虛引用對(duì)象入隊(duì),這樣就可以知道哪些對(duì)象被回收,從而對(duì)它們關(guān)聯(lián)的資源做進(jìn)一步處理

  3. 典型例子是 Cleaner 釋放 DirectByteBuffer 關(guān)聯(lián)的直接內(nèi)存

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

引用隊(duì)列詳解:如圖,虛引用關(guān)聯(lián)的對(duì)象a,b被釋放內(nèi)存后,虛引用本身會(huì)被放到引用隊(duì)列里,由Reference Handler 線程專門負(fù)責(zé)回收他們,因?yàn)樗麄兛赡苓€關(guān)聯(lián)了其他一些資源(不僅僅只是a對(duì)象和b對(duì)象)

代碼說(shuō)明

  • day03.reference.TestPhantomReference - 演示虛引用的基本用法
  • day03.reference.TestWeakReference - 模擬 ThreadLocalMap, 采用引用隊(duì)列釋放 entry 內(nèi)存
String str = new String("hello"); // "hello"在堆內(nèi)存中 (new出來(lái)的都在堆中)
String str = "hello"; // "hello" 在常量池中 

ThreadLocalMap 中的 Entry 對(duì)象,key是弱引用,value是強(qiáng)引用
java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize
上圖就是一種典型的內(nèi)存泄露
解決:使用引用隊(duì)列,將Entry和某個(gè)引用隊(duì)列關(guān)聯(lián)上,當(dāng)Entry的key被回收時(shí),整個(gè)Entry對(duì)象會(huì)被放到引用隊(duì)列里面去,然后直接將已經(jīng)在引用隊(duì)列中的Entry對(duì)象的Map引用去掉就行了(或者說(shuō)看看當(dāng)前Entry在不在Map中,在就將Map里面記錄Entry的數(shù)組對(duì)應(yīng)引用設(shè)置為null),沒有引用指向它,下次回收時(shí)就會(huì)被回收了
jdk不是這么實(shí)現(xiàn)的,成本會(huì)比較高

★★★key就是ThreadLocal對(duì)象本身,線程運(yùn)行時(shí)一定還被其他對(duì)象強(qiáng)引用,所以不怕他被設(shè)置為弱引用,線程沒有結(jié)束前,key(有其他強(qiáng)引用)不會(huì)被釋放。但是value一旦設(shè)置為弱引用,真的就只有這一個(gè)弱引用了,很可能線程還沒結(jié)束,就被GC回收了?!铩铩?/mark>

7. finalize

要求

  • 掌握 finalize 的工作原理與缺點(diǎn)

finalize

  • 一般回答:它是 Object 中的一個(gè)方法,如果子類重寫它,垃圾回收時(shí)此方法會(huì)被調(diào)用,可以在其中進(jìn)行資源釋放和清理工作
  • 優(yōu)秀回答:將資源釋放和清理放在 finalize 方法中非常不好,非常影響性能,嚴(yán)重時(shí)甚至?xí)?OOM(Out of Memory),從 Java9 開始就被標(biāo)注為 @Deprecated,不建議被使用了

追問(wèn):為什么非常不好,非常影響性能?
見下面原理:

補(bǔ):守護(hù)線程,在主線程已經(jīng)結(jié)束時(shí),守護(hù)線程就不會(huì)再執(zhí)行了(即使有代碼沒執(zhí)行完畢)

finalize 原理

  1. 對(duì) finalize 方法進(jìn)行處理的核心邏輯位于 java.lang.ref.Finalizer 類中,它包含了名為 unfinalized 的靜態(tài)變量(雙向鏈表結(jié)構(gòu)),F(xiàn)inalizer 也可被視為另一種引用對(duì)象(地位與軟、弱、虛相當(dāng),只是不對(duì)外,無(wú)法直接使用)
  2. 當(dāng)重寫了 finalize 方法的對(duì)象,在構(gòu)造方法調(diào)用之時(shí),JVM 都會(huì)將其包裝成一個(gè) Finalizer 對(duì)象,并加入 unfinalized 鏈表中 (表示這些對(duì)象的finalize方法還沒有被調(diào)用哦,不要輕易釋放它 (也是此引用鏈的作用))

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. Finalizer 類中還有另一個(gè)重要的靜態(tài)變量,即 ReferenceQueue 引用隊(duì)列 (類似前面四種引用里面的引用隊(duì)列,輔助釋放引用對(duì)象本身(幫助釋放關(guān)聯(lián)的一些其他資源) 區(qū)別在于加入隊(duì)列時(shí)關(guān)聯(lián)的對(duì)象暫時(shí)不能被回收,因?yàn)橐日{(diào)用 finalize 方法),剛開始它是空的。當(dāng)狗對(duì)象可以被當(dāng)作垃圾回收時(shí),就會(huì)把這些狗對(duì)象對(duì)應(yīng)的 Finalizer 對(duì)象加入此引用隊(duì)列
  2. 但此時(shí) Dog 對(duì)象還沒法被立刻回收,因?yàn)?unfinalized -> Finalizer 這一引用鏈還在引用它嘛,為的是【先別著急回收啊,等我調(diào)完 finalize 方法,再回收】
  3. FinalizerThread 線程會(huì)從 ReferenceQueue 中逐一取出每個(gè) Finalizer 對(duì)象,把它們從鏈表斷開并真正調(diào)用 finallize 方法

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize

  1. 由于整個(gè) Finalizer 對(duì)象已經(jīng)從 unfinalized 鏈表中斷開,這樣沒誰(shuí)能引用到它和狗對(duì)象,所以下次 gc 時(shí)就被回收了

finalize 缺點(diǎn)

  • 無(wú)法保證資源釋放:FinalizerThread 是守護(hù)線程,代碼很有可能沒來(lái)得及執(zhí)行完,線程就結(jié)束了
  • 無(wú)法判斷是否發(fā)生錯(cuò)誤:執(zhí)行 finalize 方法時(shí),會(huì)吞掉任意異常(Throwable try-catch給吞了)
  • 內(nèi)存釋放不及時(shí):重寫了 finalize 方法的對(duì)象在第一次被 gc 時(shí),并不能及時(shí)釋放它占用的內(nèi)存,因?yàn)橐戎?FinalizerThread 調(diào)用完 finalize,把它從 unfinalized 隊(duì)列移除后,第二次 gc 時(shí)才能真正釋放內(nèi)存
  • 有的文章提到【Finalizer 線程會(huì)和我們的主線程進(jìn)行競(jìng)爭(zhēng),不過(guò)由于它的優(yōu)先級(jí)較低,獲取到的CPU時(shí)間較少,因此它永遠(yuǎn)也趕不上主線程的步伐】這個(gè)顯然是錯(cuò)誤的,F(xiàn)inalizerThread 的優(yōu)先級(jí)較普通線程更高(max-2=8 普通線程都才5),原因應(yīng)該是 finalize 串行執(zhí)行慢等原因綜合導(dǎo)致(隊(duì)列上取一個(gè)調(diào)用一個(gè)finalize )

代碼說(shuō)明

  • day03.reference.TestFinalize - finalize 的測(cè)試代碼

java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-491341.html

到了這里,關(guān)于java面經(jīng)03-虛擬機(jī)篇-jvm內(nèi)存結(jié)構(gòu)&垃圾回收、內(nèi)存溢出&類加載、引用&悲觀鎖&HashTable、引用&finalize的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【Java虛擬機(jī)】JVM垃圾回收機(jī)制和常見回收算法原理

    【Java虛擬機(jī)】JVM垃圾回收機(jī)制和常見回收算法原理

    1.垃圾回收機(jī)制 (1)什么是垃圾回收機(jī)制(Garbage Collection, 簡(jiǎn)稱GC) 指自動(dòng)管理動(dòng)態(tài)分配的內(nèi)存空間的機(jī)制,自動(dòng)回收不再使用的內(nèi)存,以避免內(nèi)存泄漏和內(nèi)存溢出的問(wèn)題 最早是在1960年代提出的,程序員需要手動(dòng)管理內(nèi)存的分配和釋放 這往往會(huì)導(dǎo)致內(nèi)存泄漏和內(nèi)存溢出等問(wèn)

    2024年02月02日
    瀏覽(37)
  • [AIGC] 深入理解 Java 虛擬機(jī)(JVM)的垃圾回收

    [AIGC] 深入理解 Java 虛擬機(jī)(JVM)的垃圾回收

    一、是什么 Java 虛擬機(jī)(JVM)的垃圾回收(Garbage Collection)是一種自動(dòng)內(nèi)存管理機(jī)制,用于釋放不再使用的對(duì)象所占用的內(nèi)存空間。垃圾回收的目標(biāo)是回收那些不再被程序引用的對(duì)象,以避免內(nèi)存泄漏和內(nèi)存溢出等問(wèn)題。 二、為什么需要垃圾回收 在 Java 程序中,對(duì)象的創(chuàng)建

    2024年02月21日
    瀏覽(16)
  • JVM | 垃圾回收器(GC)- Java內(nèi)存管理的守護(hù)者

    JVM | 垃圾回收器(GC)- Java內(nèi)存管理的守護(hù)者

    在編程世界中, 有效的內(nèi)存管理 是至關(guān)重要的。這不僅確保了應(yīng)用程序的穩(wěn)定運(yùn)行,還可以大大提高性能和響應(yīng)速度。作為世界上最受歡迎的編程語(yǔ)言之一,通過(guò)Java虛擬機(jī)內(nèi)部的垃圾回收器組件來(lái)自動(dòng)管理內(nèi)存,是成為之一的其中一項(xiàng)必不可少的技術(shù)點(diǎn)。 在許多傳統(tǒng)的編程

    2024年02月09日
    瀏覽(29)
  • JVM03-優(yōu)化垃圾回收

    JVM03-優(yōu)化垃圾回收

    ? ? ? ?JVM的內(nèi)存區(qū)域中,程序計(jì)數(shù)器、虛擬機(jī)棧和本地方法棧這3個(gè)區(qū)域是線程私有的,隨著線程的創(chuàng)建而創(chuàng)建,銷毀而銷毀;棧中的棧幀隨著方法的進(jìn)入和退出進(jìn)行入棧和出棧操作,每個(gè)棧幀中分配多少內(nèi)存基本是在類結(jié)構(gòu)確定下來(lái)的時(shí)候就已知的,因此這三個(gè)區(qū)域的內(nèi)存

    2024年02月12日
    瀏覽(17)
  • 【Java高級(jí)應(yīng)用:深入探索Java編程的強(qiáng)大功能,JVM 類加載機(jī)制, JVM 內(nèi)存模型,垃圾回收機(jī)制,JVM 字節(jié)碼執(zhí)行,異常處理機(jī)制】

    本人詳解 作者:王文峰,參加過(guò) CSDN 2020年度博客之星,《Java王大師王天師》 公眾號(hào):JAVA開發(fā)王大師,專注于天道酬勤的 Java 開發(fā)問(wèn)題 中國(guó)國(guó)學(xué)、傳統(tǒng)文化和代碼愛好者的程序人生,期待你的關(guān)注和支持!本人外號(hào):神秘小峯 山峯 轉(zhuǎn)載說(shuō)明:務(wù)必注明來(lái)源(注明:作者:

    2024年01月16日
    瀏覽(27)
  • jvm垃圾回收及內(nèi)存模型

    jvm垃圾回收及內(nèi)存模型

    1、了解垃圾回收之前,必須先了解內(nèi)存模型 jdk1.8后,元空間是 方法區(qū)的具體實(shí)現(xiàn) (方法區(qū)是規(guī)范,之前叫永久代) ? 1)運(yùn)行時(shí)常量池? 就是字節(jié)碼生成的Class對(duì)象包含上述的常量池 ? ? ? 2、垃圾回收區(qū)域 ? ?a、 首先要標(biāo)記垃圾,找出垃圾 ? ? ?b、Java垃圾回收(一)_java 垃

    2024年02月08日
    瀏覽(21)
  • JVM之內(nèi)存與垃圾回收篇2

    JVM之內(nèi)存與垃圾回收篇2

    PC Register是唯一一個(gè)在Java虛擬機(jī)規(guī)范中沒有規(guī)定任何OutOfMemoryError的區(qū)域。 為什么要有PC寄存器? 因?yàn)镃PU會(huì)在不同的線程之間來(lái)回切換,切換回來(lái)之后,需要知道接著從哪里開始執(zhí)行。 JVM字節(jié)碼解釋器需要通過(guò)改變PC寄存器中的值來(lái)明確下一條應(yīng)該執(zhí)行什么樣的字節(jié)碼指令。

    2024年02月17日
    瀏覽(24)
  • JVM—內(nèi)存管理(運(yùn)行時(shí)數(shù)據(jù)區(qū))、垃圾回收

    JVM—內(nèi)存管理(運(yùn)行時(shí)數(shù)據(jù)區(qū))、垃圾回收

    當(dāng)JVM類加載器加載完字節(jié)碼文件之后,會(huì)交給執(zhí)行引擎執(zhí)行,在執(zhí)行的過(guò)程中會(huì)有一塊JVM內(nèi)存區(qū)域來(lái)存放程序運(yùn)行過(guò)程中的數(shù)據(jù),也就是我們圖中放的運(yùn)行時(shí)數(shù)據(jù)區(qū),那這一塊運(yùn)行時(shí)數(shù)據(jù)區(qū)究竟幫我們做了哪些工作?我們常說(shuō)的線上內(nèi)存泄漏和內(nèi)存溢出是因?yàn)槭裁??我們今?/p>

    2024年02月13日
    瀏覽(29)
  • JVM學(xué)習(xí)之內(nèi)存與垃圾回收篇1

    JVM學(xué)習(xí)之內(nèi)存與垃圾回收篇1

    2000年,JDK 1.3發(fā)布,Java Hot Spot Virtual Machine正式發(fā)布,成為Java的默認(rèn)虛擬機(jī)。 2006年,JDK 6發(fā)布。同年,Java開源并建立了OpenJDK。順理成章,Hotspot虛擬機(jī)也成為了OpenJDK中的默認(rèn)虛擬機(jī)。 2008年,Oracle收購(gòu)了BEA,得到了JRockit虛擬機(jī)。 2010年,Oracle收購(gòu)了Sun,獲得了Java的商標(biāo)和Ho

    2024年02月16日
    瀏覽(41)
  • JVM 垃圾回收詳解之內(nèi)存分配和回收原則+死亡對(duì)象判斷方法

    JVM 垃圾回收詳解之內(nèi)存分配和回收原則+死亡對(duì)象判斷方法

    當(dāng)需要排查各種內(nèi)存溢出問(wèn)題、當(dāng)垃圾收集成為系統(tǒng)達(dá)到更高并發(fā)的瓶頸時(shí),我們就需要對(duì)這些“自動(dòng)化”的技術(shù)實(shí)施必要的監(jiān)控和調(diào)節(jié)。 Java 的自動(dòng)內(nèi)存管理主要是針對(duì)對(duì)象內(nèi)存的回收和對(duì)象內(nèi)存的分配。同時(shí),Java 自動(dòng)內(nèi)存管理最核心的功能是 堆 內(nèi)存中對(duì)象的分配與回收

    2023年04月19日
    瀏覽(40)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包