《深入理解Java虛擬機(jī)-JVM高級特性與最佳實踐》學(xué)習(xí)總結(jié)(第三章)

首先針對垃圾收集提出的兩個問題肘迎?

  1. 什么時候回收?
  2. 怎么回收?

針對問題1妓布,為了回答什么時候回收這個問題窿侈,就需要清楚處于怎樣狀態(tài)下的對象才需要回收。

處于怎樣狀態(tài)下的對象才需要回收秋茫?在強引用下史简,只有當(dāng)對象失去所有引用的時候,才要對其進(jìn)行回收肛著。

那么如何判斷對象處于是否引用的狀態(tài)呢圆兵?

目前有兩種主流辦法:

  • 引用計數(shù)法

引用計數(shù)法是指每個對象都有一個引用計數(shù)器,每當(dāng)該對象被引用枢贿,計數(shù)器加1殉农,失去一個引用,計數(shù)器減1局荚。如果該對象的計數(shù)器值為0時超凳,則說明該對象無任何引用。

該方法的優(yōu)勢:判定效率高

劣勢:解決不了"循環(huán)引用"問題

那么耀态,何為循環(huán)引用呢轮傍?

舉個例子:

//jack所引用的對象引用計數(shù)加1,reference = 1
Student jack = new Student();

//lucy所引用的對象引用計數(shù)加1,reference = 1
Student lucy = new Student();

//jack.goodFriend所引用的對象(即為jack所引用的對象)引用計數(shù)加1,reference = 2
jack.goodFriend = lucy;

//jack.goodFriend所引用的對象(即為lucy所引用的對象)引用計數(shù)加1,reference = 2
lucy.goodFriend = jack;

//jack.goodFriend所引用的對象(即為jack所引用的對象)引用計數(shù)減1,reference = 1
jack = null;

//jack.goodFriend所引用的對象(即為lucy所引用的對象)引用計數(shù)減1,reference = 1
lucy = null;

** 在該例子中,雖然兩個對象還都有引用計數(shù)首装,但是經(jīng)過 jack = nulllucy = null 之后创夜,都無法再訪問這兩個對象了。所以由于這個劣勢仙逻,在java中并沒有使用到它驰吓,相反,使用的下面這種垃圾收集搜索算法 **

  • 根搜索算法

根搜索算法是指:通過一系列名為"GC Roots"的對象作為起始點系奉,從這些節(jié)點起開始向下搜索檬贰,搜索所走過的路徑成為引用鏈(Reference Chain),當(dāng)一個對象到GC Roots沒有任何引用鏈相連缺亮,即該對象到GC Roots不可達(dá)時翁涤,則此對象已經(jīng)失去所有引用,已不可用了瞬内。

那么迷雪,哪些對象可以充當(dāng)GC Roots對象呢?(為什么呢虫蝶?)

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

擴(kuò)展章咧,"引用"這個詞語,在Java里面的意思可有很多呢能真,光我知道就至少有四個赁严,它們分別是:

  • 強引用(Strong References)

對于強引用扰柠,則是我們經(jīng)常在程序里面new一個對象,即 Boy boy = new Boy(),只要boy不置為null,則我們new的這個對象就會一直存在,垃圾收集器這家伙就不敢拿它怎么辦疼约。

  • 軟引用(Soft References)

對于軟引用的聲明 SoftReference<T> softReference = new SoftReference<T>(Object obj);

具體例子: SoftReference<T> softReference = new SoftReference<T>(new Boy());

這個時候該Boy()實例就持有一個強引用boy和一個軟引用softReference卤档。

那么該軟引用softReference有什么用呢?

當(dāng)boy = null 的時候程剥,此時可以通過softReference.get()方法來重新獲得一個Boy的強引用劝枣。那么我就在想了,為什么要存在這個軟引用呢织鲸?我再用一個強引用指向Boy不也可以嗎舔腾?

先來看一下軟引用的特點:

該軟引用的確可以重新獲得一個該對象的強引用,而且該軟引用指向的對象也不會被垃圾收集器給收集搂擦,但是一旦JVM發(fā)現(xiàn)內(nèi)存不夠稳诚,那接下來就要對這些軟引用開刀了---對它們所引用的對象進(jìn)行收集,以獲得所需要的內(nèi)存瀑踢。而一旦垃圾收集結(jié)束扳还,該softReference.get()方法返回的便是null了。所以橱夭,軟引用這種引用可以幫助我們再次獲得強引用氨距,但是它也有可能會被清理掉。

那么這種特點的意義何在徘钥?

軟引用指向一個對象衔蹲,一塊內(nèi)存,但是該對象我們有可能會使用到它呈础,所以我們需要一個get()方法來立即獲得該對象的一個強引用,但是也可能不會使用到它橱健,可這樣的話而钞,這個對象又占著一塊內(nèi)存資源,所以我認(rèn)為在這里JVM非常巧妙地采取了一種折中辦法拘荡,在內(nèi)存不夠,OutOfMemory的時候臼节,就要把這個對象給回收掉,空出多余的內(nèi)存供系統(tǒng)正常使用珊皿。實在是妙呀网缝!那么在什么應(yīng)用場景下會使用到軟引用呢?通過對軟引用的了解蟋定,我認(rèn)為在對數(shù)據(jù)粉臊、資源進(jìn)行緩存的時候需要用到,有些非必須資源我們可以用一個軟引用持有驶兜,當(dāng)還沒被回收掉的時候扼仲,可以提升應(yīng)用程序的性能远寸,而當(dāng)內(nèi)存不夠,需要回收的時候屠凶,那就給回收掉驰后,也沒什么太大的損失。

  • 弱引用(Weak References)

弱引用是什么矗愧?

聲明一個弱引用WeakReference<T> weakWidget = new WeakReference<T>(Object obj)

舉個例子:WeakReference<T> weakReference = new WeakReference<T>(new Boy());
這個時候weakReference就是作為一個指向Boy對象的弱引用灶芝。

那么這個弱引用有什么特點呢?

在JVM中唉韭,如果一個對象被一個弱引用所指向夜涕,那么該對象首先會在第一次垃圾收集周期被標(biāo)記(沒有任何條件,直接就會被標(biāo)記)纽哥,然后在第二次垃圾收集周期被回收掉钠乏。

不過在JAVA中提供了一個WeakHashMap()類,根據(jù)名字就可以得知這個類的一些基本用法了春塌。WeakHashMap()類中的key為弱引用類型晓避,value則為實例對象。當(dāng)key所引用的對象被清理掉之后只壳,該WeakHashMap()則會自動調(diào)用remove()方法來將對應(yīng)的一組key-value給刪除掉俏拱。

那么弱引用的這種特點有什么作用嗎?

在學(xué)習(xí)這個弱引用的時候吼句,查閱了許多的英文資料锅必,不同的資料描述不一樣,但是基本上說的還都是同一個東西惕艳。于此同時又對比了一下軟引用搞隐,個人認(rèn)為弱引用和它的功能比較類似,也是作為數(shù)據(jù)远搪、資源緩存的一個很好的API劣纲,但之所以弱引用中有一個 "弱"字,就是因為該類型的引用不需要任何條件谁鳍,直接就會被標(biāo)記為垃圾癞季,然后接下來一步就會被清理掉。所以在清理之前倘潜,我們可以通過 weakReference.get()來再次獲得一個該對象的引用绷柒,等到清理掉之后,返回的就是null涮因。

4.虛引用(Phantom References)

虛引用可以理解為該引用指向了一個已經(jīng)調(diào)用過一次finalize()方法的對象废睦,那么再下一次垃圾收集的時候,就果斷將該對象給回收掉蕊退。虛引用是引用中最弱最弱的一種郊楣,以至于調(diào)用get()方法返回值始終都是null憔恳。

虛引用的清除過程大概是怎樣的呢?

Java提供了一個ReferenceQueue類净蚤,即為引用隊列類钥组,JVM會將該虛引用入隊到該ReferenceQueue,等到出隊的時候今瀑,也就是對象回收的時候程梦,與此同時,也會給系統(tǒng)發(fā)送一個信號橘荠,表示該對象已被回收屿附。

所以根據(jù)"對象被回收要接受到信號"這個特性,我們便先人一步知道了該對象被回收的時間哥童,這個時候我們可以做一些后續(xù)的操作挺份。

好了,總結(jié)完了對象何時會被回收之后贮懈,接下來要看看對象是如何被回收的匀泊。提到"如何"二字,如果用編程的思想來考慮的話朵你,就是設(shè)計算法的問題了各聘。

所以在"如何回收對象"這個問題上,JVM給我們提供了四種方法來解決抡医。

  • 標(biāo)記-清除(Mark-Sweep)算法
標(biāo)記-清除

簡述一下該算法:該算法分為兩個階段:標(biāo)記清除 階段躲因。
在標(biāo)記階段,JVM所要做的事情有忌傻,給待回收的對象做上標(biāo)記大脉。
在清除階段,JVM則會命令垃圾收集器在一次垃圾回收的時候?qū)σ呀?jīng)被標(biāo)記的對象進(jìn)行大清理水孩。

但是箱靴,該算法存在怎樣的問題呢?

會有內(nèi)存碎片的產(chǎn)生

那么產(chǎn)生內(nèi)存碎片有什么危害嗎荷愕?

內(nèi)存碎片一旦產(chǎn)生,就意味著我們的一部分內(nèi)存就被分割成一塊一塊較小的內(nèi)存了棍矛,這樣每當(dāng)有占有內(nèi)存較大的對象要來分配的話安疗,我們沒有足夠的內(nèi)存來提供,但是這個對象又不可能不給人家分配內(nèi)分對不對够委?所以JVM就不得不再次把垃圾收集器給叫過來荐类,說:"看吧,都說了不建議你用這種 標(biāo)記-清除方式 方法來干活茁帽,你就是不聽玉罐,看看現(xiàn)在麻煩來了吧屈嗤?你趕緊再去收集一次垃圾吧,抓緊騰出一塊地方給剛剛那個新來的客人吊输,人家是客饶号,我們可惹不起"。垃圾收集器受到老大的這般訓(xùn)斥后季蚂,就趕緊屁顛屁顛地跑過去干活了茫船。

  • 標(biāo)記-整理(Mark-Compact)算法
標(biāo)記-整理

簡述一下該算法:該算法與上一次算法的不同之處就在于,當(dāng)每個待回收的對象被做上標(biāo)記之后扭屁,垃圾收集器先不著急把它們一個個地給回收掉算谈,而且先粗中有細(xì)地先把每個對象進(jìn)行一個整理,怎么整理呢料滥?將被標(biāo)記的對象從第一個到最后一個依次有序地重新排列在內(nèi)存的一端然眼,然后再給一鍋端了,這樣做的好處與第一個算法相比葵腹,好處自然是大大的高每,為什么呢?因為不會產(chǎn)生內(nèi)存碎片呀礁蔗!

注意:該算法一般用在老年代內(nèi)存區(qū)

  • 復(fù)制(Copying)算法
復(fù)制算法

簡述一下該算法:"復(fù)制"二字觉义,我們可以大概猜測這種算法可能是要復(fù)制一塊內(nèi)存吧?沒錯浴井,準(zhǔn)確地說晒骇,這種算法它會將內(nèi)存分為均等的兩份cake1和cake2,每份一模一樣磺浙,不多也不少洪囤。然后在為對象分配內(nèi)存的時候,會先在cake1上分配撕氧。最后當(dāng)cake1上的內(nèi)存被用光瘤缩,要用到cake2內(nèi)存的時候,就會先去cake1上檢測哪些對象是可回收的伦泥,哪些是不可回收的剥啤。對于暫時還不可回收的對象,我們就直接將其依次有序地復(fù)制到cake2上不脯,對于那些可回收的對象府怯,就果斷讓垃圾收集器過來把它們統(tǒng)統(tǒng)給趕走。這樣一來防楷,我們的cake1就又完全變成一塊嶄新等待開發(fā)的內(nèi)存了牺丙。這樣每當(dāng)再次需要為對象分配內(nèi)存的時候,就在cake2上進(jìn)行复局,接下來的過程就像第一次一樣冲簿,循環(huán)交互粟判,協(xié)同工作。

這種算法的優(yōu)點:很明顯峦剔,這種算法也不會產(chǎn)生內(nèi)存碎片(其實只要不是隨意地對對象進(jìn)行回收档礁,回收之前或者之后稍微做一些處理,都不會產(chǎn)生內(nèi)存碎片的)羊异,而且實現(xiàn)簡單事秀,運行高效。

不過上面的那一種算法只是剛誕生時候的設(shè)計野舶,它將內(nèi)存按照1:1的比例來分配易迹,這樣有時候會造成50%的內(nèi)存浪費,這對于程序員來說真得很讓人痛心平道,那么這種算法有沒有什么改進(jìn)呢睹欲?

引用一段來自周志明先生所著的《深入理解Java虛擬機(jī)——JVM高級特性與最佳實踐(第2版)》的原話:

IBM的專門研究表明,新生代中的對象98%是朝生夕死的一屋,所以并不需要按照1:1的比例來劃分內(nèi)存空間窘疮。而是將內(nèi)存分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次需要為對象分配內(nèi)存的時候就現(xiàn)在Eden和其中的一塊Survivor冀墨。當(dāng)回收時闸衫,將Eden和Survivor中還存活著的對象一次性拷貝到另外一個Survivor空間上,最后清理掉Eden和剛才用過的Survivor的空間诽嘉。HotSpot虛擬機(jī)默認(rèn)Eden和Survivor的大小比例是8:1蔚出,也就是每次新生代中可用內(nèi)存空間為整個新生代容量的90%,只有10%的內(nèi)存是會被"浪費"的虫腋。

從這段話中我知道了原來該算法將內(nèi)存劃分比例從1:1調(diào)整到了8:1骄酗,其中劃分了三個區(qū)域:Eden和兩個Survivor,然后內(nèi)存分配首先在Eden和一塊Surivor上(也就是我的那個cake1)悦冀,然后
當(dāng)一次垃圾收集到來的時候趋翻,會根據(jù)上邊復(fù)制算法描述的那樣,該轉(zhuǎn)移的轉(zhuǎn)移盒蟆,該清除的清除踏烙。不過轉(zhuǎn)移的內(nèi)存是第二塊Survivor區(qū)域。

看完這本書里面的這段描述之后历等,覺得豁然開朗宙帝。但是隨著思維的慣性又思考下去,發(fā)現(xiàn)遇到了一個問題:如果第二塊Survivor的內(nèi)存不夠存儲轉(zhuǎn)移的對象了該怎么辦募闲?就不存儲內(nèi)存了嗎?或者會發(fā)生內(nèi)存溢出嗎愿待?又接著看下去發(fā)現(xiàn)原來書中對我這個疑惑給予了一定的解釋浩螺,他是這樣說的

當(dāng)然靴患,98%的對象可回收只是一般場景下的數(shù)據(jù),我們沒有辦法保證每次回收都只有不多余10%的對象存活要出,當(dāng)Survivor空間不夠用時鸳君,需要依賴其他內(nèi)存(這里指老年代)進(jìn)行分配擔(dān)保(Handle Promotion)。

有了這段話的解釋患蹂,就多多少少解決了一些我的疑惑或颊。不過又發(fā)現(xiàn)這兩段引用中,有兩個詞不是太理解传于,一個叫"新生代"囱挑,一個叫"老年代"。這兩個**代指的又是什么呢沼溜?

4.分代收集(Generational Collection)算法

簡述一下分代收集算法:"分代"是指根據(jù)對象的存活周期的不同把內(nèi)存劃分為幾塊平挑,一般是把java堆分為新生代和老年代。哈哈系草,這里終于提到了"新生代"和"老年代"啦通熄!那么,它倆具體指什么呢找都?

看一下這本書對其的簡單介紹:

在新生代中唇辨,每次垃圾收集時都會有大批對象死去,只有少量存活能耻。那就選用復(fù)制算法赏枚,只需要付出少量存活對象的復(fù)制成本就可以完成收集。而老年代中因為對象存活率高嚎京,沒有額外空間對它進(jìn)行分配擔(dān)保嗡贺,就必須使用"標(biāo)記-清理"或"標(biāo)記-整理"算法來進(jìn)行回收。

真好鞍帝,不光介紹了這兩個代诫睬,而且把我剛剛學(xué)過的那些算法也用在相應(yīng)了代上了。根據(jù)復(fù)制算法的特點我知道了何時選擇它帕涌,當(dāng)大部分對象處于"朝生夕死"摄凡,使用次數(shù)不多的時候,這種算法就突顯出了它的優(yōu)勢:內(nèi)存浪費少蚓曼,不會產(chǎn)生內(nèi)存碎片亲澡,并且實現(xiàn)簡單,運行高效纫版。而當(dāng)對象存活率高的時候床绪,就用那兩個標(biāo)記算法。

垃圾收集器

前邊學(xué)習(xí)了垃圾收集都有哪些算法,那么接下來就要來了解一下運行這些垃圾收集算法的東西癞己,那就是垃圾收集器膀斋。

垃圾收集器的分類

HotSpot虛擬機(jī)的垃圾收集器

Serial收集器

Serial收集器是最基本、歷史最悠久的收集器痹雅,在JDK1.3.1之前是虛擬機(jī)新生代收集的唯一選擇仰担。

特點:單線程,簡單高效(因為沒有線程交互所帶來的系統(tǒng)開銷)绩社,進(jìn)行垃圾收集時需要暫停其他所有線程(stop the world)摔蓝,所以就會有一定的卡頓現(xiàn)象。

Serial垃圾收集器

應(yīng)用:虛擬機(jī)在Clinet模式下的默認(rèn)新生代收集器愉耙。

ParNew收集器

ParNew收集器是Serial收集器的多線程版本贮尉。

特點:多線程,速度相對較慢(因為有線程交互所帶來的系統(tǒng)開銷)劲阎,進(jìn)行垃圾收集時需要暫停其他所有進(jìn)程

ParNew垃圾收集器

應(yīng)用:虛擬機(jī)在Server模式下首選的新生代收集器绘盟,不過為什么呢?目前除了Serial收集器外悯仙,目前只有它能與CMS收集器配合工作龄毡。

Parallel Scavenge收集器

Parallel Scavenge收集器是一個多線程的新生代收集器,使用復(fù)制算法锡垄。

特點:多線程沦零,吞吐量優(yōu)先

所謂吞吐量是指:CPU運行用戶代碼的時間與CPU總消耗時間的比值,即吞吐量 = 運行用戶代碼時間 / (運行用戶代碼時間 + 垃圾收集時間)

Serial Old收集器

Serial Old收集器是Serial收集器的單線程老年代版本货岭,使用"標(biāo)記-整理"算法

特點:適用于老年代路操,單線程

Serial Old垃圾收集器

應(yīng)用:
虛擬機(jī)在Client模式下使用該收集器;
在Server模式下千贯,在JDK1.5及之前的版本中與Parallel Scavenge收集器搭配使用作為CMD收集器的后備預(yù)案屯仗,在并發(fā)收集發(fā)生Concurrent Mode Failure的時候使用。

Parallel Old收集器

Parallel Old收集器是Parallel Scavenge收集器的老年代版本搔谴,使用多線程和"標(biāo)記-整理"算法紊遵。

特點:適用于老年代夯秃,多線程

Parallel Old垃圾收集器

應(yīng)用:在注重吞吐量及CPU資源敏感的場合难咕,優(yōu)先考慮Parallel Scavenge收集器和Parallel Old收集器

CMS收集器

CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標(biāo)的收集器回怜,基于"標(biāo)記-清除"算法。

收集過程:
1.初始標(biāo)記(CMS initial mark)

特點:單線程芜果,stop the world

作用:僅僅是標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對象鞠呈,速度很快

2.并發(fā)標(biāo)記(CMS concurrent mark)

特點:單線程,與其他線程并發(fā)運行

3.重新標(biāo)記(CMS remark)

特點:多線程右钾,stop the world

作用:修正并發(fā)標(biāo)記期間蚁吝,因用戶程序繼續(xù)運行而導(dǎo)致標(biāo)記產(chǎn)生變動的那一部分對象的標(biāo)記記錄旱爆。

4.并發(fā)清除(CMS concurrent sweep)

特點:單線程,與其他線程并發(fā)運行

CMS垃圾收集器

應(yīng)用:服務(wù)端

很明顯的缺點:

1.對CPU資源敏感灭将。CMS默認(rèn)啟動的回收線程(CPU數(shù)量 + 3) / 4 疼鸟,當(dāng)CPU >= 4的時候,并發(fā)回收時垃圾收集線程最多占用不超過25%的CPU資源庙曙,但是當(dāng)CPU < 4 的時候,CMS對用戶程序的影響就可能變得很大浩淘。

2.CMS無法處理"浮動垃圾"(Floating Garbage)捌朴,可能出現(xiàn)"Concurrent Mode Failure"失敗而導(dǎo)致另一次Full GC的產(chǎn)生。 什么是"浮動垃圾"呢张抄?在CMS結(jié)束標(biāo)記之后砂蔽,有一部分對象也成可以被清理的垃圾了,可CMS無法在本次的垃圾處理過程中回收掉它們署惯,所以又動態(tài)產(chǎn)生的這部分垃圾叫做"浮動垃圾"左驾。在CMS運行的同時,也有用戶線程在運行极谊,所以就需要預(yù)留夠足夠的內(nèi)存空間給用戶線程诡右,而當(dāng)CMS不能保證這一點的時候,就會出現(xiàn)"Concurrent Mode Failure"這種錯誤轻猖。

3.CMS基于的"標(biāo)記-清除"算法會產(chǎn)生內(nèi)存碎片帆吻。(不過CMS較好地解決了這種問題,解決的辦法便是在經(jīng)過一次的CMS垃圾處理過程服務(wù)之后咙边,還會再送一個碎片整理服務(wù))

G1收集器

G1收集器是當(dāng)前收集器技術(shù)發(fā)展的最前沿成果猜煮,基于"標(biāo)記-整理"算法,

特點:能夠精確地控制停頓败许,可以實現(xiàn)在基本不犧牲吞吐量的前提下完成低停頓的內(nèi)存回收王带。

那么,為什么有以上優(yōu)點呢市殷?引用一段來自《深入理解Java虛擬機(jī)-JVM高級特性與最佳實踐》

G1收集器極力地避免全區(qū)域的垃圾收集愕撰,之前的收集器進(jìn)行收集的范圍都是整個新生代或老年代,而G1將整個JAVA堆(包括新生代被丧、老年代)劃分為多個大小固定的獨立區(qū)域(Region)盟戏,并且跟蹤這些區(qū)域里面的垃圾堆積程度,在后臺維護(hù)一個優(yōu)先列表甥桂,每次根據(jù)允許的收集時間柿究,優(yōu)先回收垃圾最多的區(qū)域(Garbage First名字的由來)。這樣一來黄选,區(qū)域劃分以及有優(yōu)先級的區(qū)域回收蝇摸,保證了G1收集器在有限的時間內(nèi)可以獲得最高的收集效率

內(nèi)存分配與回收策略

1.對象優(yōu)先在Eden分配

大多數(shù)情況下婶肩,對象在新生代Eden區(qū)中分配。當(dāng)Eden區(qū)沒有足夠的空間進(jìn)行分配時貌夕,虛擬機(jī)將發(fā)起一次Minor Gc(新生代垃圾收集律歼,復(fù)制算法)。

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

1.什么是大對象啡专?

需要大量連續(xù)內(nèi)存空間的Java對象(很長的字符串和數(shù)組)

那么险毁,這樣的大對象為什么要直接進(jìn)入老年代呢?

因為經(jīng)常出現(xiàn)大對象容易導(dǎo)致內(nèi)存還有不少空間時就提前觸發(fā)垃圾收集以獲取足夠的連續(xù)空間來"安置"它們们童。所以畔况,虛擬機(jī)提供了一個-XX:PretenureSizeThreshold參數(shù),如果所需內(nèi)存值超過該參數(shù)值慧库,就直接在老年代中分配跷跪,這樣就直接避免了新生代區(qū)頻繁地進(jìn)行GC操作了。

3.長期存活的對象將進(jìn)入老年代

如何衡量一個對象的存活時間呢齐板?

JVM為每個對象設(shè)置了一個對象年齡計數(shù)器吵瞻,每一次進(jìn)行分代收集之后,如果位于新生代的對象還沒有被收集的話甘磨,該年齡計數(shù)器加1橡羞,如果該值超過一個閥值(默認(rèn)為15歲),則該對象會被調(diào)入到老年代中去享缚淼担咯尉姨!

4.動態(tài)對象年齡判定

這是另一種可以進(jìn)入老年代的途徑:如果在Survivor空間中相同年齡所有對象大小的總和大于Survivor空間的一半,年齡大于或等于該年齡的對象就可以直接進(jìn)入老年代吗冤,而無須等待到當(dāng)初設(shè)定的那個閥值又厉。

5.空間分配擔(dān)保

JVM將內(nèi)存分為新生代和老年代,在新生代又分為一個Eden區(qū)和兩個Survivor區(qū)域椎瘟,在進(jìn)行垃圾收集的時候覆致,第二塊Survivor區(qū)域用于存儲還存活的對象,但是有可能會存在所有存活對象所占內(nèi)存過多肺蔚,導(dǎo)致Survivor區(qū)域不夠用煌妈,這個時候就要向老年代區(qū)域申請擔(dān)保,把多余的對象放在老年區(qū)宣羊。不過此時需要有一個對老年區(qū)是否也能存放得下這些對象的一個評估璧诵,那就是根據(jù)之前每次晉升到老年代的平均大小是否大于老年代的剩余空間大小,

如果大于的話仇冯,就意味著此次的對象有很大的可能性是晉升不到老年代區(qū)的之宿,意思就是老年代內(nèi)存有很大可能是不夠用的,那么該怎么做呢苛坚?只能把老年代區(qū)進(jìn)行一次Full GC 來騰出一些空間了比被。

但是如果平均大小小于剩余空間的話色难,那就意味著有很大可能性是能夠晉升的,那么就趕緊把這些對象給放進(jìn)老年代區(qū)嗎等缀?等等枷莉!這里還有一個HandlePromotionFailure設(shè)置選項,該選項的意思是是否允許擔(dān)保失敗(這里是有可能失敗的)尺迂。如果允許笤妙,一旦老年代區(qū)放不下,那就立馬在新生代區(qū)執(zhí)行MinorGC垃圾收集過程噪裕。如果不允許的話危喉,一旦老年代放不下,那就要在老年代立馬進(jìn)行一次Full GC垃圾收集了州疾。這樣,無論哪種情況發(fā)生皇拣,我們要么在新生代進(jìn)行MinorGC或者在老年代進(jìn)行FullGC严蓖,這樣總能盡最大可能來為對象分配內(nèi)存空間。

參考資料

英文資料一

英文資料二

書籍:《深入理解Java虛擬機(jī)-JVM高級特性與最佳實踐》周志強

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末氧急,一起剝皮案震驚了整個濱河市颗胡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌吩坝,老刑警劉巖毒姨,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異钉寝,居然都是意外死亡弧呐,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門嵌纲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來俘枫,“玉大人,你說我怎么就攤上這事逮走○剑” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵师溅,是天一觀的道長茅信。 經(jīng)常有香客問我,道長墓臭,這世上最難降的妖魔是什么蘸鲸? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮起便,結(jié)果婚禮上棚贾,老公的妹妹穿的比我還像新娘窖维。我一直安慰自己,他們只是感情好妙痹,可當(dāng)我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布铸史。 她就那樣靜靜地躺著,像睡著了一般怯伊。 火紅的嫁衣襯著肌膚如雪琳轿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天耿芹,我揣著相機(jī)與錄音崭篡,去河邊找鬼。 笑死吧秕,一個胖子當(dāng)著我的面吹牛琉闪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播砸彬,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼颠毙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了砂碉?” 一聲冷哼從身側(cè)響起蛀蜜,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎增蹭,沒想到半個月后滴某,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡滋迈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年霎奢,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片杀怠。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡椰憋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出赔退,到底是詐尸還是另有隱情橙依,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布硕旗,位于F島的核電站窗骑,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏漆枚。R本人自食惡果不足惜创译,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望墙基。 院中可真熱鬧软族,春花似錦刷喜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至颗祝,卻和暖如春浊闪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背螺戳。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工搁宾, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人倔幼。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓盖腿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親损同。 傳聞我的和親對象是個殘疾皇子奸忽,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容