久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Java之美[從菜鳥(niǎo)到高手演變]之JVM內(nèi)存管理及垃圾回收

 指尖幻城 2017-01-02

很多Java面試的時(shí)候,都會(huì)問(wèn)到有關(guān)Java垃圾回收的問(wèn)題,,提到垃圾回收肯定要涉及到JVM內(nèi)存管理機(jī)制,,Java語(yǔ)言的執(zhí)行效率一直被C、C++程序員所嘲笑,,其實(shí),,事實(shí)就是這樣,Java在執(zhí)行效率方面確實(shí)很低,,一方面,,Java語(yǔ)言采用面向?qū)ο笏枷耄@也決定了其必然是開(kāi)發(fā)效率高,,執(zhí)行效率低,。另一方面,Java語(yǔ)言對(duì)程序員做了一個(gè)美好的承諾:程序員無(wú)需去管理內(nèi)存,,因?yàn)镴VM有垃圾回收(GC),,會(huì)去自動(dòng)進(jìn)行垃圾回收。

其實(shí)不然:

1,、垃圾回收并不會(huì)按照程序員的要求,,隨時(shí)進(jìn)行GC。

2,、垃圾回收并不會(huì)及時(shí)的清理內(nèi)存,,盡管有時(shí)程序需要額外的內(nèi)存。

3,、程序員不能對(duì)垃圾回收進(jìn)行控制,。

因?yàn)樯厦孢@些事實(shí),以致我們?cè)趯?xiě)程序的時(shí)候,只能根據(jù)垃圾回收的規(guī)律,,合理安排內(nèi)存,,這就要求我們必須徹底了解JVM的內(nèi)存管理機(jī)制,這樣才能隨心所欲,,將程序控制于鼓掌之中,!本章系Java之美[從菜鳥(niǎo)到高手演變]系列之JVM內(nèi)存管理及垃圾回收,學(xué)完本章知識(shí),,讀者對(duì)JVM就會(huì)有基本的了解,。

本博客永久更新,如有轉(zhuǎn)載,,

請(qǐng)說(shuō)明出處:http://blog.csdn.net/zhangerqing

如有問(wèn)題,,請(qǐng)聯(lián)系本人: egg

郵箱:[email protected]

微博:http://weibo.com/xtfggef

一、JVM內(nèi)存的構(gòu)

Java虛擬機(jī)會(huì)將內(nèi)存分為幾個(gè)不同的管理區(qū),,這些區(qū)域各自有各自的用途,,根據(jù)不同的特點(diǎn),承擔(dān)不同的任務(wù)以及在垃圾回收時(shí)運(yùn)用不同的算法,??傮w分為下面幾個(gè)部分:

程序計(jì)數(shù)器(Program Counter Register)、JVM虛擬機(jī)棧(JVM Stacks),、本地方法棧(Native Method Stacks),、堆(Heap)、方法區(qū)(Method Area)

如下圖:

1,、程序計(jì)數(shù)器(Program Counter Register)

這是一塊比較小的內(nèi)存,,不在Ram上,而是直接劃分在CPU上的,,程序員無(wú)法直接操作它,,它的作用是:JVM在解釋字節(jié)碼文件(.class)時(shí),存儲(chǔ)當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào),,只是一種概念模型,,各種JVM所采用的方式不同,字節(jié)碼解釋器工作時(shí),,就是通過(guò)改變程序計(jì)數(shù)器的值來(lái)選取下一條要執(zhí)行的指令,,分支、循環(huán),、跳轉(zhuǎn),、等基礎(chǔ)功能都是依賴此技術(shù)區(qū)完成的。還有一種情況,,就是我們常說(shuō)的Java多線程方面的,,多線程就是通過(guò)現(xiàn)程輪流切換而達(dá)到的,,同一時(shí)刻,一個(gè)內(nèi)核只能執(zhí)行一個(gè)指令,,所以,,對(duì)于每一個(gè)程序來(lái)說(shuō),,必須有一個(gè)計(jì)數(shù)器來(lái)記錄程序的執(zhí)行進(jìn)度,,這樣,當(dāng)現(xiàn)程恢復(fù)執(zhí)行的時(shí)候,,才能從正確的地方開(kāi)始,,所以,每個(gè)線程都必須有一個(gè)獨(dú)立的程序計(jì)數(shù)器,,這類(lèi)計(jì)數(shù)器為線程私有的內(nèi)存,。如果一個(gè)線程正在執(zhí)行一個(gè)Java方法,則計(jì)數(shù)器記錄的是字節(jié)碼的指令的地址,,如果執(zhí)行的一個(gè)Native方法,,則計(jì)數(shù)器的記錄為空,此內(nèi)存區(qū)是唯一一個(gè)在Java規(guī)范中沒(méi)有任何OutOfMemoryError情況的區(qū)域,。

2,、JVM虛擬機(jī)棧(JVM Stacks)

JVM虛擬機(jī)棧就是我們常說(shuō)的堆棧的棧(我們常常把內(nèi)存粗略分為堆和棧),和程序計(jì)數(shù)器一樣,,也是線程私有的,,生命周期和線程一樣,每個(gè)方法被執(zhí)行的時(shí)候會(huì)產(chǎn)生一個(gè)棧幀,,用于存儲(chǔ)局部變量表,、動(dòng)態(tài)鏈接、操作數(shù),、方法出口等信息,。方法的執(zhí)行過(guò)程就是棧幀在JVM中出棧和入棧的過(guò)程。局部變量表中存放的是各種基本數(shù)據(jù)類(lèi)型,,如boolean,、byte、char,、等8種,,及引用類(lèi)型(存放的是指向各個(gè)對(duì)象的內(nèi)存地址),因此,,它有一個(gè)特點(diǎn):內(nèi)存空間可以在編譯期間就確定,,運(yùn)行期不在改變。這個(gè)內(nèi)存區(qū)域會(huì)有兩種可能的Java異常:StackOverFlowError和OutOfMemoryError,。

3,、本地方法棧(Native Method Stacks)

從名字即可看出,,本地方法棧就是用來(lái)處理Java中的本地方法的,Java類(lèi)的祖先類(lèi)Object中有眾多Native方法,,如hashCode(),、wait()等,他們的執(zhí)行很多時(shí)候是借助于操作系統(tǒng),,但是JVM需要對(duì)他們做一些規(guī)范,,來(lái)處理他們的執(zhí)行過(guò)程。此區(qū)域,,可以有不同的實(shí)現(xiàn)方法,,向我們常用的Sun的JVM就是本地方法棧和JVM虛擬機(jī)棧是同一個(gè)。

4,、堆(Heap)

堆內(nèi)存是內(nèi)存中最重要的一塊,,也是最有必要進(jìn)行深究的一部分。因?yàn)镴ava性能的優(yōu)化,,主要就是針對(duì)這部分內(nèi)存的,。所有的對(duì)象實(shí)例及數(shù)組都是在堆上面分配的(隨著JIT技術(shù)的逐漸成熟,這句話視乎有些絕對(duì),,不過(guò)至少目前還基本是這樣的),,可通過(guò)-Xmx和-Xms來(lái)控制堆的大小。JIT技術(shù)的發(fā)展產(chǎn)生了新的技術(shù),,如棧上分配和標(biāo)量替換,,也許在不久的幾年里,即時(shí)編譯會(huì)誕生及成熟,,那個(gè)時(shí)候,,“所有的對(duì)象實(shí)例及數(shù)組都是在堆上面分配的”這句話就應(yīng)該稍微改改了。堆內(nèi)存是垃圾回收的主要區(qū)域,,所以在下文垃圾回收板塊會(huì)重點(diǎn)介紹,,此處只做概念方面的解釋。在32位系統(tǒng)上最大為2G,,64位系統(tǒng)上無(wú)限制,。可通過(guò)-Xms和-Xmx控制,,-Xms為JVM啟動(dòng)時(shí)申請(qǐng)的最小Heap內(nèi)存,,-Xmx為JVM可申請(qǐng)的最大Heap內(nèi)存。

5,、方法區(qū)(Method Area)

 方法區(qū)是所有線程共享的內(nèi)存區(qū)域,,用于存儲(chǔ)已經(jīng)被JVM加載的類(lèi)信息、常量,、靜態(tài)變量等數(shù)據(jù),,一般來(lái)說(shuō),,方法區(qū)屬于持久代(關(guān)于持久代,會(huì)在GC部分詳細(xì)介紹,,除了持久代,,還有新生代和舊生代),也難怪Java規(guī)范將方法區(qū)描述為堆的一個(gè)邏輯部分,,但是它不是堆,。方法區(qū)的垃圾回收比較棘手,就算是Sun的HotSpot VM在這方面也沒(méi)有做得多么完美,。此處引入方法區(qū)中一個(gè)重要的概念:運(yùn)行時(shí)常量池,。主要用于存放在編譯過(guò)程中產(chǎn)生的字面量(字面量簡(jiǎn)單理解就是常量)和引用。一般情況,,常量的內(nèi)存分配在編譯期間就能確定,但不一定全是,,有一些可能就是運(yùn)行時(shí)也可將常量放入常量池中,,如String類(lèi)中有個(gè)Native方法intern()<關(guān)于intern()的詳細(xì)說(shuō)明,請(qǐng)看另一篇文章:http://blog.csdn.net/zhangerqing/article/details/8093919>

此處補(bǔ)充一個(gè)在JVM內(nèi)存管理之外的一個(gè)內(nèi)存區(qū):直接內(nèi)存,。在JDK1.4中新加入類(lèi)NIO類(lèi),,引入了一種基于通道與緩沖區(qū)的I/O方式,它可以使用Native函數(shù)庫(kù)直接分配堆外內(nèi)存,,即我們所說(shuō)的直接內(nèi)存,,這樣在某些場(chǎng)景中會(huì)提高程序的性能。

二,、垃圾回收

有句話說(shuō)的好:Java和C++之間有一堵有內(nèi)存分配和垃圾回收技術(shù)圍成的墻,,墻外的人想進(jìn)去,墻里的人想出去,!這句話的意思,,請(qǐng)讀者自己去琢磨??偟膩?lái)說(shuō),,C、C++程序員有時(shí)苦于內(nèi)存泄露,,內(nèi)存管理是件令人頭痛的事兒,,但是Java程序員呢,又羨慕C++程序員,,自己可以控制一切,,這樣就不會(huì)在內(nèi)存管理方面顯得束手無(wú)策,,的卻如此,,作為Java程序員我們很難去控制JVM的內(nèi)存回收,只能根據(jù)它的原理去適應(yīng),,盡量提高程序的性能,。下面開(kāi)始講解Java垃圾回收,,即Garbage Collection,GC,。從以下四個(gè)方面進(jìn)行:

1,、為什么要進(jìn)行垃圾回收?

隨著程序的運(yùn)行,,內(nèi)存中存在的實(shí)例對(duì)象,、變量等信息占據(jù)的內(nèi)存越來(lái)越多,如果不及時(shí)進(jìn)行垃圾回收,,必然會(huì)帶來(lái)程序性能的下降,,甚至?xí)驗(yàn)榭捎脙?nèi)存不足造成一些不必要的系統(tǒng)異常。

2,、哪些“垃圾”需要回收,?

在我們上面介紹的五大區(qū)中,有三個(gè)是不需要進(jìn)行垃圾回收的:程序計(jì)數(shù)器,、JVM棧,、本地方法棧,。因?yàn)樗鼈兊纳芷谑呛途€程同步的,,隨著線程的銷(xiāo)毀,它們占用的內(nèi)存會(huì)自動(dòng)釋放,,所以只有方法區(qū)和堆需要進(jìn)行GC,。具體到哪些對(duì)象的話,簡(jiǎn)單概況一句話:如果某個(gè)對(duì)象已經(jīng)不存在任何引用,,那么它可以被回收,。通俗解釋一下就是說(shuō),如果一個(gè)對(duì)象,,已經(jīng)沒(méi)有什么作用了,就可以被當(dāng)廢棄物被回收了,。

3,、什么時(shí)候進(jìn)行垃圾回收,?

根據(jù)一個(gè)經(jīng)典的引用計(jì)數(shù)算法,每個(gè)對(duì)象添加一個(gè)引用計(jì)數(shù)器,,每被引用一次,計(jì)數(shù)器加1,,失去引用,,計(jì)數(shù)器減1,,當(dāng)計(jì)數(shù)器在一段時(shí)間內(nèi)保持為0時(shí),該對(duì)象就認(rèn)為是可以被回收得了,。但是,這個(gè)算法有明顯的缺陷:當(dāng)兩個(gè)對(duì)象相互引用,,但是二者已經(jīng)沒(méi)有作用時(shí),按照常規(guī),,應(yīng)該對(duì)其進(jìn)行垃圾回收,但是其相互引用,,又不符合垃圾回收的條件,,因此無(wú)法完美處理這塊內(nèi)存清理,,因此Sun的JVM并沒(méi)有采用引用計(jì)數(shù)算法來(lái)進(jìn)行垃圾回收。而是采用一個(gè)叫:根搜索算法,,如下圖:

基本思想就是:從一個(gè)叫GC Roots的對(duì)象開(kāi)始,向下搜索,如果一個(gè)對(duì)象不能到達(dá)GC Roots對(duì)象的時(shí)候,,說(shuō)明它已經(jīng)不再被引用,即可被進(jìn)行垃圾回收(此處 暫且這樣理解,,其實(shí)事實(shí)還有一些不同,,當(dāng)一個(gè)對(duì)象不再被引用時(shí),并沒(méi)有完全“死亡”,,如果類(lèi)重寫(xiě)了finalize()方法,且沒(méi)有被系統(tǒng)調(diào)用過(guò),,那么系統(tǒng)會(huì)調(diào)用一次finalize()方法,,以完成最后的工作,在這期間,,如果可以將對(duì)象重新與任何一個(gè)和GC Roots有引用的對(duì)象相關(guān)聯(lián),,則該對(duì)象可以“重生”,,如果不可以,,那么就說(shuō)明徹底可以被回收了),如上圖中的Object5、Object6、Object7,,雖然它們3個(gè)依然可能相互引用,但是總體來(lái)說(shuō),它們已經(jīng)沒(méi)有作用了,,這樣就解決了引用計(jì)數(shù)算法無(wú)法解決的問(wèn)題。

補(bǔ)充引用的概念JDK 1.2之后,對(duì)引用進(jìn)行了擴(kuò)充,,引入了強(qiáng)、軟,、若、虛四種引用,被標(biāo)記為這四種引用的對(duì)象,,在GC時(shí)分別有不同的意義:

    a> 強(qiáng)引用(Strong Reference).就是為剛被new出來(lái)的對(duì)象所加的引用,它的特點(diǎn)就是,,永遠(yuǎn)不會(huì)被回收,。

    b> 軟引用(Soft Reference).聲明為軟引用的類(lèi),是可被回收的對(duì)象,如果JVM內(nèi)存并不緊張,,這類(lèi)對(duì)象可以不被回收,,如果內(nèi)存緊張,則會(huì)被回收,。此處有一個(gè)問(wèn)題,,既然被引用為軟引用的對(duì)象可以回收,為什么不去回收呢,?其實(shí)我們知道,,Java中是存在緩存機(jī)制的,就拿字面量緩存來(lái)說(shuō),,有些時(shí)候,,緩存的對(duì)象就是當(dāng)前可有可無(wú)的,只是留在內(nèi)存中如果還有需要,,則不需要重新分配內(nèi)存即可使用,,因此,這些對(duì)象即可被引用為軟引用,,方便使用,,提高程序性能。

    c> 弱引用(Weak Reference).弱引用的對(duì)象就是一定需要進(jìn)行垃圾回收的,,不管內(nèi)存是否緊張,,當(dāng)進(jìn)行GC時(shí),標(biāo)記為弱引用的對(duì)象一定會(huì)被清理回收,。

    d> 虛引用(Phantom Reference).虛引用弱的可以忽略不計(jì),,JVM完全不會(huì)在乎虛引用,其唯一作用就是做一些跟蹤記錄,,輔助finalize函數(shù)的使用,。

最后總結(jié),什么樣的類(lèi)需要回收呢,?無(wú)用的類(lèi),何為無(wú)用的類(lèi),?需滿足如下要求:

   1> 該類(lèi)的所有實(shí)例對(duì)象都已經(jīng)被回收,。

   2> 加載該類(lèi)的ClassLoader已經(jīng)被回收,。

   3> 該類(lèi)對(duì)應(yīng)的反射類(lèi)java.lang.Class對(duì)象沒(méi)有被任何地方引用,。

4,、如何進(jìn)行垃圾回收,?

本塊內(nèi)容以介紹垃圾回收算法為主,因?yàn)槲覀兦懊嬗薪榻B,,內(nèi)存主要被分為三塊,,新生代,、舊生代,、持久代,。三代的特點(diǎn)不同,,造就了他們所用的GC算法不同,,新生代適合那些生命周期較短,,頻繁創(chuàng)建及銷(xiāo)毀的對(duì)象,,舊生代適合生命周期相對(duì)較長(zhǎng)的對(duì)象,持久代在Sun HotSpot中就是指方法區(qū)(有些JVM中根本就沒(méi)有持久代這中說(shuō)法)。首先介紹下新生代,、舊生代,、持久代的概念及特點(diǎn):

新生代:New Generation或者Young Generation,。上面大致分為Eden區(qū)和Survivor區(qū),,Survivor區(qū)又分為大小相同的兩部分:FromSpace 和ToSpace,。新建的對(duì)象都是用新生代分配內(nèi)存,,Eden空間不足的時(shí)候,,會(huì)把存活的對(duì)象轉(zhuǎn)移到Survivor中,,新生代的大小可以由-Xmn來(lái)控制,,也可以用-XX:SurvivorRatio來(lái)控制Eden和Survivor的比例.
舊生代:Old Generation。用于存放新生代中經(jīng)過(guò)多次垃圾回收仍然存活的對(duì)象,例如緩存對(duì)象,。舊生代占用大小為-Xmx值減去-Xmn對(duì)應(yīng)的值。

持久代:Permanent Generation,。在Sun的JVM中就是方法區(qū)的意思,盡管有些JVM大多沒(méi)有這一代,。主要存放常量及類(lèi)的一些信息默認(rèn)最小值為16MB,,最大值為64MB,可通過(guò)-XX:PermSize及-XX:MaxPermSize來(lái)設(shè)置最小值和最大值,。

常見(jiàn)的GC算法:

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

最基礎(chǔ)的GC算法,,將需要進(jìn)行回收的對(duì)象做標(biāo)記,之后掃描,,有標(biāo)記的進(jìn)行回收,,這樣就產(chǎn)生兩個(gè)步驟:標(biāo)記和清除。這個(gè)算法效率不高,,而且在清理完成后會(huì)產(chǎn)生內(nèi)存碎片,,這樣,如果有大對(duì)象需要連續(xù)的內(nèi)存空間時(shí),,還需要進(jìn)行碎片整理,,所以,此算法需要改進(jìn),。

復(fù)制算法(Copying)

前面我們談過(guò),,新生代內(nèi)存分為了三份,Eden區(qū)和2塊Survivor區(qū),,一般Sun的JVM會(huì)將Eden區(qū)和Survivor區(qū)的比例調(diào)為8:1,,保證有一塊Survivor區(qū)是空閑的,這樣,在垃圾回收的時(shí)候,,將不需要進(jìn)行回收的對(duì)象放在空閑的Survivor區(qū),,然后將Eden區(qū)和第一塊Survivor區(qū)進(jìn)行完全清理,這樣有一個(gè)問(wèn)題,,就是如果第二塊Survivor區(qū)的空間不夠大怎么辦,?這個(gè)時(shí)候,就需要當(dāng)Survivor區(qū)不夠用的時(shí)候,,暫時(shí)借持久代的內(nèi)存用一下,。此算法適用于新生代

標(biāo)記-整理(或叫壓縮)算法(Mark-Compact)

和標(biāo)記-清楚算法前半段一樣,,只是在標(biāo)記了不需要進(jìn)行回收的對(duì)象后,,將標(biāo)記過(guò)的對(duì)象移動(dòng)到一起,使得內(nèi)存連續(xù),,這樣,只要將標(biāo)記邊界以外的內(nèi)存清理就行了,。此算法適用于持久代,。

常見(jiàn)的垃圾收集器: 

根據(jù)上面說(shuō)的諸多算法,每天JVM都有不同的實(shí)現(xiàn),,我們先來(lái)看看常見(jiàn)的一些垃圾收集器:


首先介紹三種實(shí)際的垃圾回收器:串行GC(SerialGC),、并行回收GC(Parallel Scavenge)和并行GC(ParNew)。

1,、Serial GC,。是最基本、最古老的收集器,,但是現(xiàn)在依然被廣泛使用,,是一種單線程垃圾回收機(jī)制,而且不僅如此,,它最大的特點(diǎn)就是在進(jìn)行垃圾回收的時(shí)候,,需要將所有正在執(zhí)行的線程暫停(Stop The World),對(duì)于有些應(yīng)用這是難以接受的,,但是我們可以這樣想,,只要我們能夠做到將它所停頓的時(shí)間控制在N個(gè)毫秒范圍內(nèi),大多數(shù)應(yīng)用我們還是可以接受的,,而且事實(shí)是它并沒(méi)有讓我們失望,,幾十毫米的停頓我們作為客戶機(jī)(Client)是完全可以接受的,該收集器適用于單CPU,、新生代空間較小及對(duì)暫停時(shí)間要求不是非常高的應(yīng)用上,,是client級(jí)別默認(rèn)的GC方式,可以通過(guò)-XX:+UseSerialGC來(lái)強(qiáng)制指定。

2,、ParNew GC,。基本和Serial GC一樣,,但本質(zhì)區(qū)別是加入了多線程機(jī)制,,提高了效率,這樣它就可以被用在服務(wù)器端(Server)上,,同時(shí)它可以與CMS GC配合,,所以,更加有理由將它置于Server端,。

3,、Parallel Scavenge GC。在整個(gè)掃描和復(fù)制過(guò)程采用多線程的方式來(lái)進(jìn)行,,適用于多CPU,、對(duì)暫停時(shí)間要求較短的應(yīng)用上,是server級(jí)別默認(rèn)采用的GC方式,,可用-XX:+UseParallelGC來(lái)強(qiáng)制指定,,用-XX:ParallelGCThreads=4來(lái)指定線程數(shù)。以下給出幾組使用組合:


4,、CMS (Concurrent Mark Sweep)收集器,。該收集器目標(biāo)就是解決Serial GC 的停頓問(wèn)題,以達(dá)到最短回收時(shí)間,。常見(jiàn)的B/S架構(gòu)的應(yīng)用就適合用這種收集器,,因?yàn)槠涓卟l(fā)、高響應(yīng)的特點(diǎn),。CMS收集器是基于“標(biāo)記-清除”算法實(shí)現(xiàn)的,,整個(gè)收集過(guò)程大致分為4個(gè)步驟:

初始標(biāo)記(CMS initial mark)、并發(fā)標(biāo)記(CMS concurrenr mark),、重新標(biāo)記(CMS remark),、并發(fā)清除(CMS concurrent sweep)。

其中初始標(biāo)記,、重新標(biāo)記這兩個(gè)步驟任然需要停頓其他用戶線程,。初始標(biāo)記僅僅只是標(biāo)記出GC ROOTS能直接關(guān)聯(lián)到的對(duì)象,速度很快,,并發(fā)標(biāo)記階段是進(jìn)行GC ROOTS 根搜索算法階段,,會(huì)判定對(duì)象是否存活。而重新標(biāo)記階段則是為了修正并發(fā)標(biāo)記期間,,因用戶程序繼續(xù)運(yùn)行而導(dǎo)致標(biāo)記產(chǎn)生變動(dòng)的那一部分對(duì)象的標(biāo)記記錄,,這個(gè)階段的停頓時(shí)間會(huì)被初始標(biāo)記階段稍長(zhǎng),,但比并發(fā)標(biāo)記階段要短。由于整個(gè)過(guò)程中耗時(shí)最長(zhǎng)的并發(fā)標(biāo)記和并發(fā)清除過(guò)程中,,收集器線程都可以與用戶線程一起工作,,所以整體來(lái)說(shuō),CMS收集器的內(nèi)存回收過(guò)程是與用戶線程一起并發(fā)執(zhí)行的,。

CMS收集器的優(yōu)點(diǎn):并發(fā)收集,、低停頓,但是CMS還遠(yuǎn)遠(yuǎn)達(dá)不到完美,。

CMS收集器主要有三個(gè)顯著缺點(diǎn)

a>.CMS收集器對(duì)CPU資源非常敏感,。在并發(fā)階段,雖然不會(huì)導(dǎo)致用戶線程停頓,,但是會(huì)占用CPU資源而導(dǎo)致引用程序變慢,,總吞吐量下降。CMS默認(rèn)啟動(dòng)的回收線程數(shù)是:(CPU數(shù)量+3) / 4,。

b>.CMS收集器無(wú)法處理浮動(dòng)垃圾,,可能出現(xiàn)“Concurrent Mode Failure“,失敗后而導(dǎo)致另一次Full GC的產(chǎn)生,。由于CMS并發(fā)清理階段用戶線程還在運(yùn)行,,伴隨程序的運(yùn)行自熱會(huì)有新的垃圾不斷產(chǎn)生,這一部分垃圾出現(xiàn)在標(biāo)記過(guò)程之后,,CMS無(wú)法在本次收集中處理它們,只好留待下一次GC時(shí)將其清理掉,。這一部分垃圾稱為“浮動(dòng)垃圾”,。也是由于在垃圾收集階段用戶線程還需要運(yùn)行,即需要預(yù)留足夠的內(nèi)存空間給用戶線程使用,,因此CMS收集器不能像其他收集器那樣等到老年代幾乎完全被填滿了再進(jìn)行收集,,需要預(yù)留一部分內(nèi)存空間提供并發(fā)收集時(shí)的程序運(yùn)作使用。在默認(rèn)設(shè)置下,,CMS收集器在老年代使用了68%的空間時(shí)就會(huì)被激活,,也可以通過(guò)參數(shù)-XX:CMSInitiatingOccupancyFraction的值來(lái)提供觸發(fā)百分比,以降低內(nèi)存回收次數(shù)提高性能,。要是CMS運(yùn)行期間預(yù)留的內(nèi)存無(wú)法滿足程序其他線程需要,,就會(huì)出現(xiàn)“Concurrent Mode Failure”失敗,這時(shí)候虛擬機(jī)將啟動(dòng)后備預(yù)案:臨時(shí)啟用Serial Old收集器來(lái)重新進(jìn)行老年代的垃圾收集,,這樣停頓時(shí)間就很長(zhǎng)了,。所以說(shuō)參數(shù)-XX:CMSInitiatingOccupancyFraction設(shè)置的過(guò)高將會(huì)很容易導(dǎo)致“Concurrent Mode Failure”失敗,性能反而降低,。

c>.最后一個(gè)缺點(diǎn),,CMS是基于“標(biāo)記-清除”算法實(shí)現(xiàn)的收集器,使用“標(biāo)記-清除”算法收集后,會(huì)產(chǎn)生大量碎片,??臻g碎片太多時(shí),將會(huì)給對(duì)象分配帶來(lái)很多麻煩,,比如說(shuō)大對(duì)象,,內(nèi)存空間找不到連續(xù)的空間來(lái)分配不得不提前觸發(fā)一次Full GC。為了解決這個(gè)問(wèn)題,,CMS收集器提供了一個(gè)-XX:UseCMSCompactAtFullCollection開(kāi)關(guān)參數(shù),,用于在Full GC之后增加一個(gè)碎片整理過(guò)程,還可通過(guò)-XX:CMSFullGCBeforeCompaction參數(shù)設(shè)置執(zhí)行多少次不壓縮的Full GC之后,,跟著來(lái)一次碎片整理過(guò)程,。

5、G1收集器,。相比CMS收集器有不少改進(jìn),,首先基于標(biāo)記-整理算法,不會(huì)產(chǎn)生內(nèi)存碎片問(wèn)題,,其次,,可以比較精確的控制停頓,此處不再詳細(xì)介紹,。

6,、Serial Old。Serial Old是Serial收集器的老年代版本,,它同樣使用一個(gè)單線程執(zhí)行收集,,使用“標(biāo)記-整理”算法。主要使用在Client模式下的虛擬機(jī),。

7,、Parallel Old。Parallel Old是Parallel Scavenge收集器的老年代版本,,使用多線程和“標(biāo)記-整理”算法,。

8、RTSJ垃圾收集器,,用于Java實(shí)時(shí)編程,,后續(xù)會(huì)補(bǔ)充介紹。

三,、Java程序性能優(yōu)化

gc()的調(diào)用

調(diào)用gc 方法暗示著Java 虛擬機(jī)做了一些努力來(lái)回收未用對(duì)象,,以便能夠快速地重用這些對(duì)象當(dāng)前占用的內(nèi)存。當(dāng)控制權(quán)從方法調(diào)用中返回時(shí),,虛擬機(jī)已經(jīng)盡最大努力從所有丟棄的對(duì)象中回收了空間,,調(diào)用System.gc() 等效于調(diào)用Runtime.getRuntime().gc(),。

finalize()的調(diào)用及重寫(xiě)

gc 只能清除在堆上分配的內(nèi)存(純java語(yǔ)言的所有對(duì)象都在堆上使用new分配內(nèi)存),而不能清除棧上分配的內(nèi)存(當(dāng)使用JNI技術(shù)時(shí),可能會(huì)在棧上分配內(nèi)存,,例如java調(diào)用c程序,,而該c程序使用malloc分配內(nèi)存時(shí))。因此,,如果某些對(duì)象被分配了棧上的內(nèi)存區(qū)域,,那gc就管不著了,對(duì)棧上的對(duì)象進(jìn)行內(nèi)存回收就要靠finalize(),。舉個(gè)例子來(lái)說(shuō),當(dāng)java 調(diào)用非java方法時(shí)(這種方法可能是c或是c++的),在非java代碼內(nèi)部也許調(diào)用了c的malloc()函數(shù)來(lái)分配內(nèi)存,,而且除非調(diào)用那個(gè)了 free() 否則不會(huì)釋放內(nèi)存(因?yàn)閒ree()是c的函數(shù)),這個(gè)時(shí)候要進(jìn)行釋放內(nèi)存的工作,gc是不起作用的,因而需要在finalize()內(nèi)部的一個(gè)固有方法調(diào)用free()。

優(yōu)秀的編程習(xí)慣

(1)避免在循環(huán)體中創(chuàng)建對(duì)象,,即使該對(duì)象占用內(nèi)存空間不大,。
(2)盡量及時(shí)使對(duì)象符合垃圾回收標(biāo)準(zhǔn)。
(3)不要采用過(guò)深的繼承層次,。
(4)訪問(wèn)本地變量?jī)?yōu)于訪問(wèn)類(lèi)中的變量,。

本版塊會(huì)不斷更新!

四,、常見(jiàn)問(wèn)題

1,、內(nèi)存溢出

就是你要求分配的java虛擬機(jī)內(nèi)存超出了系統(tǒng)能給你的,系統(tǒng)不能滿足需求,,于是產(chǎn)生溢出,。
2、內(nèi)存泄漏

是指你向系統(tǒng)申請(qǐng)分配內(nèi)存進(jìn)行使用(new),,可是使用完了以后卻不歸還(delete),,結(jié)果你申請(qǐng)到的那塊內(nèi)存你自己也不能再訪問(wèn),該塊已分配出來(lái)的內(nèi)存也無(wú)法再使用,隨著服務(wù)器內(nèi)存的不斷消耗,,而無(wú)法使用的內(nèi)存越來(lái)越多,系統(tǒng)也不能再次將它分配給需要的程序,,產(chǎn)生泄露,。一直下去,程序也逐漸無(wú)內(nèi)存使用,,就會(huì)溢出,。

本章內(nèi)容以理論為主,后續(xù)我會(huì)不斷地增加一些實(shí)際的操作,,如驗(yàn)證垃圾回收效果,、或者內(nèi)存監(jiān)測(cè)什么的,同時(shí)也希望讀者會(huì)不斷給出指導(dǎo),、建議,,如有任何問(wèn)題,,請(qǐng)聯(lián)系:egg:

郵箱:[email protected]

微博:weibo.com/xtfggef

如有轉(zhuǎn)載,請(qǐng)說(shuō)明出處(http://blog.csdn.net/zhangerqing),,謝謝,!

The End

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多