www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁 > 單片機(jī) > 架構(gòu)師社區(qū)
[導(dǎo)讀]jvm運行時數(shù)據(jù)區(qū)Java程序啟動后,本質(zhì)上就是啟動一個jvm進(jìn)程,jvm會將自己管理的內(nèi)存劃分為幾個區(qū)域,每個區(qū)域都有自己的用途。在程序運行時的內(nèi)存區(qū)域主要可以劃分為五個,分別是:方法區(qū)、堆、虛擬機(jī)棧、本地方法棧、程序計數(shù)器??梢杂孟旅娴膱D來描述:圖1?jvm運行時數(shù)據(jù)區(qū)jvm...

jvm運行時數(shù)據(jù)區(qū)


Java程序啟動后,本質(zhì)上就是啟動一個jvm進(jìn)程,jvm會將自己管理的內(nèi)存劃分為幾個區(qū)域,每個區(qū)域都有自己的用途。在程序運行時的內(nèi)存區(qū)域主要可以劃分為五個,分別是:方法區(qū)、堆、虛擬機(jī)棧、本地方法棧、程序計數(shù)器??梢杂孟旅娴膱D來描述:

一文詳解,jvm內(nèi)存分代與垃圾回收原理

圖1?jvm運行時數(shù)據(jù)區(qū)


jvm堆內(nèi)存分代


我們創(chuàng)建的對象,都會進(jìn)入Java堆內(nèi)存中,堆內(nèi)存的分代模型分為:年輕代、老年代、永久代。


其實大部分對象的存活周期都是極短的,比如我們在方法里創(chuàng)建一個對象,離開這個方法后,這個對象的生命周期就結(jié)束了。一旦這個對象沒人使用了,就需要被jvm回收掉,釋放內(nèi)存空間。


少數(shù)對象是長期存活的,比如spring容器中創(chuàng)建的bean,一般都會一直存活在容器中。


每個對象的存活時間差別巨大,那么就需要差別化管理,就像城市規(guī)劃中,會劃分出生活區(qū),商業(yè)區(qū),制造業(yè)區(qū)。


于是jvm就有了分代模型,年輕代、老年代,jvm將堆內(nèi)存分為了這兩個區(qū)域。


年輕代,顧名思義,就是對象創(chuàng)建和使用完之后,很快就要回收的對象放在里面。


老年代呢,就是對象創(chuàng)建之后需要長期存在的對象放在里面,如下圖:

一文詳解,jvm內(nèi)存分代與垃圾回收原理

圖2 jvm堆內(nèi)存分代


堆內(nèi)存分為年輕代、老年代,這跟垃圾回收有關(guān),對于年輕代里的對象,它們的特點是創(chuàng)建之后很快就會被回收,所以需要用一種垃圾回收算法。


對于老年代里的對象,他們的特點是需要長期存在,所以需要另外一種垃圾回收算法,所以需要分成兩個區(qū)域來放不同的對象。


對象的分配與流轉(zhuǎn)


一般來說,對象都是優(yōu)先分配在年輕代的。

public?class Server {????private?static ConfigLoader loader = new ConfigLoader();????public static void main(String[] args) {????????loadLocalConfig();????????while (true) {???????? loadConfigFromRemote();????????????Thread.sleep(1000);????????}????}????????private?static?void?loadLocalConfig() {????????ConfigManager?configManager = new ConfigManager();????????configManager.load();????}????private static void loadConfigFromRemote() {????????loader.load();????}}類靜態(tài)變量loader引用的那個ConfigLoader對象,首先分配在年輕代,是長期存活在內(nèi)存里的。loadLocalConfig方法中創(chuàng)建的configManager對象也是分配在新時代里的。

一文詳解,jvm內(nèi)存分代與垃圾回收原理

?圖3 對象優(yōu)先分配在新生代

什么時候觸發(fā)新生代的垃圾回收?


當(dāng)方法loadLocalConfig執(zhí)行完后,這個方法堆棧出棧,就沒有任何局部變量引用configManager對象了。


那么jvm就會立馬回收掉分配給它的內(nèi)存嗎?


不會的!如果新生代的內(nèi)存空間,幾乎都被全部對象給占滿了!此時假設(shè)我們代碼繼續(xù)運行,需要在新生代里去分配一個對象,發(fā)現(xiàn)內(nèi)存不夠了,這個時候就會觸發(fā)一次新生代的內(nèi)存回收。


新生代內(nèi)存空間的垃圾回收,也稱之為Minor GC或Young GC,它會嘗試把新生代里沒人引用的對象給回收掉。


對象是有年齡的,如果對象在一次垃圾回收后還存活,那么它的年齡就會加1。


默認(rèn)情況下,如果成功躲過了15次垃圾回收,也就是15歲,還沒被回收掉,然后它會被轉(zhuǎn)移到Java堆內(nèi)存的老年代中去,顧名思義,老年代就是放這些年齡很大的對象。


什么情況下一個對象會被回收掉?


簡單來說一個對象不再被使用了,就會被垃圾回收掉,但jvm怎么判斷一個對象是否會繼續(xù)使用呢?


jvm使用了一種可達(dá)性分析的算法來判斷對象是不是可以被回收掉。


可達(dá)性分析法,是通過從GCRoots出發(fā),找出內(nèi)存中的引用鏈,那么鏈中的對象表示可達(dá),即不能被垃圾回收。引用鏈之外的對象即可作為垃圾回收。


jvm中GC Roots有這幾種:


  • 虛擬機(jī)棧(棧幀中的本地變量表)中引用的對象
  • 方法區(qū)中類靜態(tài)屬性引用的對象
  • 方法區(qū)中常量引用的對象
  • 本地方法棧中JNI(即一般說的native方法)中引用的對象

其中,局部變量和類靜態(tài)變量比較常見。需要注意的是,類實例變量不是GC Roots。


年輕代的垃圾回收算法


新生代內(nèi)存區(qū)域劃分為三塊:1個Eden區(qū),2個Survivor區(qū),默認(rèn)情況下Eden區(qū)占80%內(nèi)存空間,每一塊Survivor區(qū)各占10%內(nèi)存空間,


比如說新生代1G的內(nèi)存,Eden區(qū)就有800MB內(nèi)存,每一塊Survivor區(qū)就有100MB內(nèi)存,如下圖。

一文詳解,jvm內(nèi)存分代與垃圾回收原理

圖4 新生代內(nèi)存劃分


剛開始對象都是分配在Eden區(qū)內(nèi)的,如果Eden區(qū)快滿了,此時就會觸發(fā)垃圾回收。


新生代使用的復(fù)制算法,此時就會把Eden區(qū)中的存活對象都一次性轉(zhuǎn)移到一塊空著的Survivor區(qū)。survivor的中文意思是存活,顧名思義,就是放垃圾回收后存活的對象的。


接著Eden區(qū)就會被清空,然后再次分配新對象就會繼續(xù)分配到Eden區(qū)里,這樣只有Eden區(qū)和一塊Survivor區(qū)里是有對象的,其中Survivor區(qū)里放的是上一次Minor GC后存活的對象。新生代的垃圾回收就是這樣來回倒騰的。


所以1G內(nèi)存的新生代,平時可以使用的,就是Eden區(qū)和其中一塊Survivor區(qū),那么相當(dāng)于有900MB的內(nèi)存是可以使用。


這么做最大的好處,就是只有10%的內(nèi)存空間是被閑置的,90%的內(nèi)存都被用上了。新生代對象存活期很短,存活的對象也很少,所以survivor分配的區(qū)域也比較小。


對象何時進(jìn)入老年代?


對象一般優(yōu)先分配在年輕代,那么何時進(jìn)入老年代呢?有這幾種情況:


  • 躲過15次垃圾回收后


具體多少歲進(jìn)入老年代,可以通過JVM參數(shù)-XX:MaxTenuringThreshold來設(shè)置,默認(rèn)是15歲。


  • 動態(tài)年齡判斷


他的大致規(guī)則就是,假如說當(dāng)前存放對象的Survivor區(qū)域里,一批對象的總大小大于了這塊Survivor區(qū)域的內(nèi)存大小的50%,那么此時大于等于這批對象年齡的對象,就可以直接進(jìn)入老年代了。


規(guī)則看起來比較晦澀,通俗理解就是:年齡1 年齡2 年齡n的多個年齡對象總和超過了Survivor區(qū)域的50%,此時就會把年齡n以上的對象都放入老年代。


  • 大對象直接進(jìn)入老年代


多大對象算大對象,可以通過JVM參數(shù)“-XX:PretenureSizeThreshold”來設(shè)置,可以把它的值設(shè)置為字節(jié)數(shù),比如“1048576”字節(jié),就是1MB。


之所以這么做,就是要避免新生代里出現(xiàn)那種大對象,屢次躲過GC,還得把他在兩個Survivor區(qū)域里來回復(fù)制多次之后才能進(jìn)入老年代,


  • Minor GC后對象太多Survivor放不下,把這些對象直接轉(zhuǎn)移到老年代去


有可能Eden區(qū)垃圾回收后,存活的對象太多,survivor放不下只能轉(zhuǎn)移到老年代去。


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


在發(fā)生Minor GC之前,JVM會先檢查一下老年代最大可用的連續(xù)內(nèi)存空間,是否大于新生代所有對象的總大小。


因為極端的情況下,可能新生代Minor GC過后,存活對象太多了,survivor放不下。


如果說發(fā)現(xiàn)老年代的內(nèi)存大小是大于新生代所有對象的,此時就可以放心大膽的對新生代發(fā)起一次Minor GC了,因為即使Minor GC之后所有對象都存活,Survivor區(qū)放不下了,也可以轉(zhuǎn)移到老年代去。


如果Minor GC之后新生代的對象全部存活下來,然后全部需要轉(zhuǎn)移到老年代去,但是老年代空間又不夠怎么辦?


那么就要看看老年代的內(nèi)存大小,是否大于之前每一次Minor GC后進(jìn)入老年代的對象的平均大小。


如果老年代連續(xù)空閑空間大于新生代對象總大小,或者大于之前每一次Minor GC后進(jìn)入老年代對象平均大小,就只觸發(fā)Minor GC,否則就要觸發(fā)Full GC。


假如此時進(jìn)行Minor GC也有幾種可能:


(1)Minor GC過后,剩余的存活對象的大小,是小于Survivor區(qū)的大小的,那么此時存活對象進(jìn)入Survivor區(qū)域即可。


(2)Minor GC過后,剩余的存活對象的大小,是大于 Survivor區(qū)域的大小,但是是小于老年代可用內(nèi)存大小的,此時就直接進(jìn)入老年代即可。


(3)Minor GC過后,剩余的存活對象的大小,大于了Survivor區(qū)域的大小,也大于了老年代可用內(nèi)存的大小。此時老年代都放不下這些存活對象了,就會發(fā)生Handle Promotion Failure的情況,這個時候就會觸發(fā)一次Full GC。


如果要是Full GC過后,老年代還是沒有足夠的空間存放Minor GC過后的剩余存活對象,那么此時就會導(dǎo)致所謂的“OOM”內(nèi)存溢出異常了。


這段規(guī)則有點繞,所以必須畫個圖梳理下:


一文詳解,jvm內(nèi)存分代與垃圾回收原理

圖5?空間擔(dān)保機(jī)制


另外需要注意的是,上面描述的空間擔(dān)保機(jī)制是jdk6以后的,與java6之前稍稍不同。


總結(jié)下,老年代觸發(fā)垃圾回收的時機(jī):


(1)Minor GC之前,發(fā)現(xiàn)很可能Minor GC之后要進(jìn)入老年代的對象太多了,老年代放不下,此時需要提前觸發(fā)Full GC然后再帶著進(jìn)行Minor GC;


(2)Minor GC之后,發(fā)現(xiàn)剩余對象太多,老年代都放不下了。


老年代回收,一般使用的標(biāo)記整理算法,首先標(biāo)記出來老年代當(dāng)前存活的對象。


接著會讓這些存活對象在內(nèi)存里進(jìn)行移動,把存活對象盡量都挪動到一起去,讓存活對象緊湊的靠在一起,避免垃圾回收過后出現(xiàn)過多的內(nèi)存碎片,然后再一次性把垃圾對象都回收掉。


總結(jié):


老年代存活對象比較多,存活對象比較大,所以老年代垃圾回收算法的速度至少比新生代的垃圾回收算法的速度慢10倍。


如果系統(tǒng)頻繁出現(xiàn)老年代的Full GC垃圾回收,會導(dǎo)致系統(tǒng)性能被嚴(yán)重影響,出現(xiàn)頻繁卡頓的情況。


所以所謂JVM優(yōu)化,就是盡可能讓對象都在新生代里分配和回收,盡量別讓太多對象頻繁進(jìn)入老年代,避免頻繁對老年代進(jìn)行垃圾回收,同時給系統(tǒng)充足的內(nèi)存大小,避免新生代頻繁的進(jìn)行垃圾回收。

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動電源

在工業(yè)自動化蓬勃發(fā)展的當(dāng)下,工業(yè)電機(jī)作為核心動力設(shè)備,其驅(qū)動電源的性能直接關(guān)系到整個系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護(hù)是驅(qū)動電源設(shè)計中至關(guān)重要的兩個環(huán)節(jié),集成化方案的設(shè)計成為提升電機(jī)驅(qū)動性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機(jī) 驅(qū)動電源

LED 驅(qū)動電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個照明設(shè)備的使用壽命。然而,在實際應(yīng)用中,LED 驅(qū)動電源易損壞的問題卻十分常見,不僅增加了維護(hù)成本,還影響了用戶體驗。要解決這一問題,需從設(shè)計、生...

關(guān)鍵字: 驅(qū)動電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動電源的公式,電感內(nèi)電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設(shè)計 驅(qū)動電源

電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動汽車的核心技術(shù)之一是電機(jī)驅(qū)動控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機(jī)驅(qū)動系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動汽車的動力性能和...

關(guān)鍵字: 電動汽車 新能源 驅(qū)動電源

在現(xiàn)代城市建設(shè)中,街道及停車場照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進(jìn)步,高亮度白光發(fā)光二極管(LED)因其獨特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動電源 LED

LED通用照明設(shè)計工程師會遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動電源

開關(guān)電源具有效率高的特性,而且開關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機(jī)重量也有所下降,所以,現(xiàn)在的LED驅(qū)動電源

關(guān)鍵字: LED 驅(qū)動電源 開關(guān)電源

LED驅(qū)動電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動電源
關(guān)閉