JVM

  • JVM的內(nèi)存劃分
  • 類加載器

四種類加載器:

  1. 啟動類加載器:C++編寫,在Java中看不到
  2. 擴(kuò)展類加載器:ExtClassLoader
  3. 應(yīng)用類加載器:AppicationClassLoader
  4. 自定義類加載器:創(chuàng)建一個類繼承java.lang.ClassLoader,定制類加載方式

關(guān)系:啟動類加載器是擴(kuò)展類加載器的父加載器,擴(kuò)展類加載器是應(yīng)用類加載器的父加載器.

雙親委派模型:

優(yōu)點(diǎn):保證了類的唯一性,避免類的重復(fù)加載,父加載器加載了某個類,子加載器就不加載了,全類名是唯一標(biāo)識

安全性考慮,比如String等Jre自帶的核心Api,由最父類的啟動類加載器加載,不由它的子類加載器惡意替換.

  • 方法棧

堆棧先進(jìn)后出,后進(jìn)先出,像是一個彈簧,壓棧,彈棧概念,方法每次被調(diào)用,都會產(chǎn)生一個棧幀,方法內(nèi)的局部變量,方法釋放,變量也釋放

棧幀的結(jié)構(gòu):

局部變量表:方法執(zhí)行時的參數(shù)、方法體內(nèi)聲明的局部變量

操作數(shù)棧:存儲中間運(yùn)算結(jié)果,是一個臨時存儲空間

幀數(shù)據(jù)區(qū):保存訪問常量池指針,異常處理表

操作數(shù)棧的存在,保存一個臨時存儲空間,例如數(shù)值交換int a = 5 和int b = 6 交換

棧溢出異常(StackOverflowErro):

例如一個沒有退出機(jī)制的遞歸方法,只占用不結(jié)束,一直產(chǎn)生棧幀,一直在申請空間,把??臻g擠滿,??臻g一直不釋放,一直在堆積,把棧內(nèi)存中的空間耗盡

某一個線程拋出『棧溢出異常』,會導(dǎo)致其他線程也崩潰嗎?

不會,線程對棧內(nèi)存空間的使用方式是彼此隔離的。每個線程都是在自己獨(dú)享的空間內(nèi)運(yùn)行,反過來也可以說,這個空間是當(dāng)前線程私有的。

工作機(jī)制:

新new出來的對象最先放在新生代的伊甸區(qū),

伊甸區(qū)的使用空間達(dá)到一定的值后觸發(fā)Minor GC垃圾回收,

沒有被這個小GC回收的會成為幸存者,去往幸存者區(qū),

幸存者區(qū)有from和to2個區(qū),(誰空誰為to區(qū),意味著這2個區(qū)是互相彼此交換的)

from區(qū)快滿了就去往了to區(qū),此時from變成了空成為了to區(qū),而to區(qū)就變成了from區(qū)

如果一個對象經(jīng)過了15次GC還沒有被垃圾回收,那么就會去往老年代區(qū)保存,

如果幸存者區(qū)滿了,即是沒有15次GC,這個對象也會去往老年代區(qū)保存

說明:

eden區(qū)存儲的主要是短暫臨時,生命周期很短的對象

幸存者區(qū)是一個中間地帶

老年代區(qū)是存放生命周期很長的對象,例如IOC管理的對象(Controller,Service,Mapper等等),線程池對象,數(shù)據(jù)庫連接池對象等等...

不被回收是因?yàn)闂V幸恢庇袀€變量指引著這個地址,相當(dāng)于有一根線連接起來了,如果這個線斷了,就是不指向這個對象的地址了,那么就會被GC垃圾回收機(jī)制回收,老年代區(qū)的對象就是一直有這根指引著

堆溢出異常(OutOfMemeory):

包括兩種Java.heap.space和PermGen space,前者是一直在new Object而且不回收,超出了堆內(nèi)存

后者PermGen space翻譯過來也很好理解,permanent generation永久代的問題,是永久代(方法去)加載的時候,類實(shí)在太多了,就導(dǎo)致方法區(qū)直接溢出了

GC的使用

為什么要GC:

程序運(yùn)行中,會產(chǎn)生很多對象,如果不處理垃圾對象,那么一直累加會導(dǎo)致內(nèi)存耗盡,程序崩潰,GC就是處理不使用的垃圾對象,釋放內(nèi)存

如何找出垃圾對象:

引用計數(shù)法(不靠譜,如果有循環(huán)引用的對象,不能夠標(biāo)記到)

可達(dá)性分析(從GC Roots對象出發(fā),不可達(dá)的對象就是要清理的對象)

GC的算法:

基本算法

引用計數(shù)法:使用引用標(biāo)記法標(biāo)記對象被引用的次數(shù),引用加1,刪除減1,當(dāng)引用計數(shù)為0 則GC

標(biāo)記清除法:當(dāng)堆的有效內(nèi)存即將耗盡的時候,暫時掛起程序(stop the world),從根對象開始遍歷所有的對象,然后再清楚所有沒有被標(biāo)記到的對象

標(biāo)記壓縮法:標(biāo)記清除法的升級,同樣當(dāng)堆有效內(nèi)存即將耗盡,暫時掛起,從根對象遍歷所有對象,然后中間多一步壓縮, 移動所有的可達(dá)對象到堆內(nèi)存的同一個區(qū)域中,使他們緊湊的排列在一起,從而將所有非可達(dá)對象釋放出來的空閑內(nèi)存都集中在一起,通過這樣的方式來達(dá)到減少內(nèi)存碎片的目的。

復(fù)制算法:復(fù)制算法的核心就是,將原有的內(nèi)存空間一分為二,每次只用其中的一塊,在垃圾回收時,將正在使用的對象復(fù)制到另一個內(nèi)存空間中,并依次排列,然后將該內(nèi)存空間清空,交換兩個內(nèi)存的角色,完成垃圾的回收。

綜合算法

分代算法:前面介紹了多種回收算法,每一種算法都有自己的優(yōu)點(diǎn)也有缺點(diǎn),誰都不能替代誰,所以根據(jù)垃圾回收對象的特點(diǎn)進(jìn)行選擇,才是明智的。分代算法其實(shí)就是這樣的,根據(jù)回收對象的特點(diǎn)進(jìn)行選擇新生代使用復(fù)制算法,老年代使用標(biāo)記清除或者標(biāo)記壓縮方法

分區(qū)算法:有點(diǎn)類似微服務(wù)那種分布式,把堆空間劃分為多個不同的小區(qū)間,每個小區(qū)間獨(dú)立使用獨(dú)立回收,這樣可以控制一次回收多個區(qū)間,并不像標(biāo)記清除和壓縮方法一樣,需要把程序全部掛起一段時間

JVM的常用參數(shù):

-Xms 堆內(nèi)存的初始化大小(建議初始化大小和最大值一樣,這樣就不需要多次提交申請)

-Xmx 堆內(nèi)存的最大值

-Xmn 新生代內(nèi)存的大小

-XX:PermSize 永久代的大小

-XX:MaxPermSize 永久代的初始化大小

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容