Java內(nèi)存管理_編寫GC友好的代碼_第1頁(yè)
Java內(nèi)存管理_編寫GC友好的代碼_第2頁(yè)
Java內(nèi)存管理_編寫GC友好的代碼_第3頁(yè)
Java內(nèi)存管理_編寫GC友好的代碼_第4頁(yè)
Java內(nèi)存管理_編寫GC友好的代碼_第5頁(yè)
已閱讀5頁(yè),還剩56頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、JVM內(nèi)存管理/GC模型/編寫GC友好的代碼關(guān)于本材料 本材料主要關(guān)心 Sun Hotspot JVM 6的內(nèi)存管理 Sun Hotspot JVM 6的GC模型 主要針對(duì)JVM6的GC模型,但也會(huì)簡(jiǎn)單介紹Java 7的G1 編寫GC友好代碼的一些技巧 參考資料 深入Java虛擬機(jī), Bill Venners The Garbage Collection Mythbusters 深入理解Java虛擬機(jī)-JVM高級(jí)特性與最佳實(shí)踐,周立明 Garbage Collection-Friendly ProgrammingJava平臺(tái)的基本概念 JVM,JRE,JDK JVM: Java Virtual

2、 Machine 負(fù)責(zé)執(zhí)行符合Java規(guī)范的Class文件 不同廠家會(huì)有不同的實(shí)現(xiàn),IBM J9, Sun Hotspot, JRockit, etc JRE: Java Runtime Environment 包括JVM和基礎(chǔ)類庫(kù)(常見的標(biāo)準(zhǔn)API,比如java.util.*, etc)。 一般來(lái)說基礎(chǔ)類庫(kù)是那些JCP大牛嘔心瀝血之作。但有些廠家也會(huì)針對(duì)自己的硬件修改一部分基礎(chǔ)類庫(kù)的實(shí)現(xiàn)。最典型的是IBM的JRE。 JDK: Java Development Kit 包括JRE和開發(fā)/編譯工具(javac, javadoc, etc)。Java平臺(tái)的基本概念JVM運(yùn)行時(shí)內(nèi)存數(shù)據(jù)區(qū)域JVM運(yùn)行

3、時(shí)數(shù)據(jù)區(qū)域 程序計(jì)數(shù)器程序計(jì)數(shù)器 本地方法棧本地方法棧 Java虛擬機(jī)棧虛擬機(jī)棧(JVM Stack) Java虛擬機(jī)棧描述的是Java方法的執(zhí)行模型:每個(gè)方法執(zhí)行的時(shí)候都會(huì)創(chuàng)建一個(gè)幀(Frame)棧用于存放局部變量表,操作棧,動(dòng)態(tài)鏈接,方法出口等信息。一個(gè)方法的執(zhí)行過程,就是這個(gè)方法對(duì)于幀棧的入棧出棧過程。 線程隔離JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)域 堆堆 (Heap) 堆里存放的是對(duì)象的實(shí)例 是Java虛擬機(jī)管理內(nèi)存中最大的一塊 GC主要的工作區(qū)域,為了高效的GC,會(huì)把堆細(xì)分更多的子區(qū)域(后面有詳細(xì)介紹) 線程共享 方法區(qū)域方法區(qū)域 Hotspot JVM的的永久代(Permanent Generati

4、on) 存放了每個(gè)Class的結(jié)構(gòu)信息,包括常量池、字段描述、方法描述 GC的非主要工作區(qū)域JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)域-例子 生成了2部分的內(nèi)存區(qū)域,1)obj這個(gè)引用變量,因?yàn)槭欠椒▋?nèi)的變量,放到JVM Stack里面 2) 真正Object class的實(shí)例對(duì)象,放到Heap里面 上述的new語(yǔ)句一共消耗12個(gè)bytes,JVM規(guī)定引用占4個(gè)bytes(在JVM Stack),而空對(duì)象是8個(gè)bytes(在Heap) 方法結(jié)束后,對(duì)應(yīng)Stack中的變量馬上回收,但是Heap中的對(duì)象要等到GC來(lái)回收J(rèn)VM垃圾回收(GC)模型 垃圾判斷算法 GC算法 垃圾回收器的實(shí)現(xiàn)和選擇垃圾判斷的算法 引用計(jì)數(shù)算法

5、(Reference Counting)給對(duì)象中添加一個(gè)引用計(jì)數(shù)器,當(dāng)有一個(gè)地方引用它,計(jì)數(shù)器加1,當(dāng)引用失效,計(jì)數(shù)器減1,任何時(shí)刻計(jì)數(shù)器為0的對(duì)象就是不可能再被使用的 。實(shí)現(xiàn)非常簡(jiǎn)單。沒辦法解決循環(huán)引用問題。比如:對(duì)象A有一個(gè)引用指向B對(duì)象,B也有一個(gè)引用指向A,如果A和B都沒有被其他對(duì)象引用,其實(shí)已經(jīng)是垃圾,但是沒辦法回收。并不實(shí)用,幾乎沒有主流的編程語(yǔ)言用這種GC判斷算法 根搜索算法(Root Tracing)通過一系列的稱為“GC Roots”的點(diǎn)作為起始進(jìn)行向下搜索,當(dāng)一個(gè)對(duì)象到GC Roots沒有任何引用鏈(Reference Chain)相連,則證明此對(duì)象是垃圾。GC Roots

6、包括: 1. JVM Stack的引用變量 2.方法區(qū)中的靜態(tài)引用 3. JNI(即一般說的Native方法)中的引用 Java, C#, Lisp等有GC特征的語(yǔ)言都是用根搜索算法JVM 常見GC算法 標(biāo)記-清除算法(Mark-Swap) 標(biāo)記-整理算法(Mark-Compact) 復(fù)制算法(Copying) 分代算法(Generational)標(biāo)記-清除算法(Mark-Swap)來(lái)自”The Garbage Collection Mythbusters”標(biāo)記-清除算法(Mark-Swap)來(lái)自”The Garbage Collection Mythbusters”標(biāo)記-清除算法(Mark-

7、Swap)來(lái)自”The Garbage Collection Mythbusters”標(biāo)記-清除算法(Mark-Swap)來(lái)自”The Garbage Collection Mythbusters”標(biāo)記-清除算法(Mark-Swap)來(lái)自”The Garbage Collection Mythbusters”標(biāo)記-清除算法(Mark-Swap)來(lái)自”The Garbage Collection Mythbusters”標(biāo)記-清除算法(Mark-Swap) 效率不高,需要掃描所有對(duì)象。堆越大,GC越慢 存在內(nèi)存碎片問題。GC次數(shù)越多,碎片越嚴(yán)重標(biāo)記-整理算法(Mark-Compact)來(lái)自”Th

8、e Garbage Collection Mythbusters”標(biāo)記-整理算法(Mark-Compact) 沒有內(nèi)存碎片 比Mark-Swap耗費(fèi)更多的時(shí)間進(jìn)行compact復(fù)制算法(Copying)來(lái)自”The Garbage Collection Mythbusters”復(fù)制算法(Copying)來(lái)自”The Garbage Collection Mythbusters”復(fù)制算法(Copying)來(lái)自”The Garbage Collection Mythbusters”復(fù)制算法(Copying)來(lái)自”The Garbage Collection Mythbusters”復(fù)制算法(Cop

9、ying)來(lái)自”The Garbage Collection Mythbusters”復(fù)制算法(Copying)來(lái)自”The Garbage Collection Mythbusters”復(fù)制算法(Copying) 只需要掃描存活的對(duì)象,效率更高 不會(huì)產(chǎn)生碎片 需要浪費(fèi)額外的內(nèi)存作為復(fù)制區(qū) 復(fù)制算法非常適合生命周期比較短的對(duì)象,因?yàn)槊看蜧C總能回收大部分的對(duì)象,復(fù)制的開銷比較小 根據(jù)IBM的專門研究,98%的Java對(duì)象只會(huì)存活1個(gè)GC周期,對(duì)這些對(duì)象很適合用復(fù)制算法。而且不用1:1的劃分工作區(qū)和復(fù)制區(qū)的空間分代算法(Generational GC) 綜合前面幾種GC算法的優(yōu)缺點(diǎn),針對(duì)不同生命

10、周期的對(duì)象采用不同的GC算法分代算法(Generational GC)Hotspot JVM 6中的共劃分為三個(gè)代:年輕代(年輕代(Young Generation)、)、年老代(年老代(Old Generation)和持久代()和持久代(Permanent Generation)。分代算法(Generational GC)年輕代(年輕代(Young Generation) 新生成的對(duì)象都放在新生代。年輕代用復(fù)制算法進(jìn)行GC(理論上,年輕代對(duì)象的生命周期非常短,所以適合復(fù)制算法) 年輕代分三個(gè)區(qū)。一個(gè)Eden區(qū),兩個(gè)Survivor區(qū)(可以通過參數(shù)設(shè)置Survivor個(gè)數(shù))。對(duì)象在Eden區(qū)中

11、生成。當(dāng)Eden區(qū)滿時(shí),還存活的對(duì)象將被復(fù)制到一個(gè)Survivor區(qū),當(dāng)這個(gè)Survivor區(qū)滿時(shí),此區(qū)的存活對(duì)象將被復(fù)制到另外一個(gè)Survivor區(qū),當(dāng)?shù)诙€(gè)Survivor去也滿了的時(shí)候,從第一個(gè)Survivor區(qū)復(fù)制過來(lái)的并且此時(shí)還存活的對(duì)象,將被復(fù)制到年老代。2個(gè)Survivor是完全對(duì)稱,輪流替換。 Eden和2個(gè)Survivor的缺省比例是8:1:1,也就是10%的空間會(huì)被浪費(fèi)??梢愿鶕?jù)GC log的信息調(diào)整大小的比例分代算法(Generational GC) 年老代(Old Generation) 存放了經(jīng)過一次或多次GC還存活的對(duì)象 一般采用Mark-Swap或者M(jìn)ark-Co

12、mpact算法進(jìn)行GC 有多種垃圾收集器可以選擇。每種垃圾收集器可以看作一個(gè)GC算法的具體實(shí)現(xiàn)。可以根據(jù)具體應(yīng)用的需求選用合適的垃圾收集器(追求吞吐量?追求最短的響應(yīng)時(shí)間?)分代算法(Generational GC) 永久代 也就是前面提到的方法區(qū),并不屬于堆(Heap).但是GC也會(huì)光顧這個(gè)區(qū)域 存放了每個(gè)Class的結(jié)構(gòu)信息,包括常量池、字段描述、方法描述。與垃圾收集要收集的Java對(duì)象關(guān)系不大GC的時(shí)機(jī) 在分代模型的基礎(chǔ)上,GC從時(shí)機(jī)上分為兩種: Scavenge GC和Full GC Scavenge GC (Minor GC) 觸發(fā)時(shí)機(jī):新對(duì)象生成時(shí),Eden空間滿了 理論上Eden

13、區(qū)大多數(shù)對(duì)象會(huì)在Scavenge GC回收,復(fù)制算法的執(zhí)行效率會(huì)很高, Scavenge GC時(shí)間比較短。 Full GC 對(duì)整個(gè)JVM進(jìn)行整理,包括Young、Old和Perm 主要的觸發(fā)時(shí)機(jī): 1)Old滿了 2)Perm滿了 3) system.gc() 效率很低,盡量減少Full GC。垃圾回收器(Garbage Collector) 分代模型:GC的戰(zhàn)略;垃圾回收器:GC的戰(zhàn)術(shù)(具體實(shí)現(xiàn)) Hotspot JVM提供多種垃圾回收器,我們需要根據(jù)具體應(yīng)用的需要采用不同的回收器 沒有萬(wàn)能的垃圾回收器,每種垃圾回收器都有自己的適用場(chǎng)景垃圾回收器的“魚與熊掌” GC時(shí)延 VS 吞吐量,二者不

14、可兼得 GC時(shí)延(GC停頓) GC是Stop the world,停頓是避免不了(哪怕Java 7最新推出的G1收集器)。收集器只能盡量減少停頓。 為了良好的用戶體驗(yàn),我們希望停頓越短越好 吞吐量 吞吐量是運(yùn)行應(yīng)用代碼所占CPU的比例 我們希望吞吐量越高越好 矛盾:為了減少停頓,需要投入更多的CPU資源去進(jìn)行GC(比如多線程的并發(fā)GC),但是會(huì)降低吞吐量 出路:根據(jù)應(yīng)用的場(chǎng)景選擇合適的收集器 對(duì)于計(jì)算密集型應(yīng)用,比如結(jié)算,計(jì)費(fèi),后臺(tái)計(jì)算等,應(yīng)該選擇偏重吞吐量的收集器 對(duì)于時(shí)延敏感的應(yīng)用,比如Web,游戲,通信等,應(yīng)該選擇偏重時(shí)延的收集器主要的垃圾回收器垃圾收集器的“并行”和“并發(fā)” 并行(Pa

15、rallel):指多個(gè)收集器的線程同時(shí)工作,但是用戶線程處于等待狀態(tài) 并發(fā)(Concurrent):指收集器在工作的同時(shí),可以允許用戶線程工作。 并發(fā)不代表解決了GC停頓的問題,在關(guān)鍵的步驟還是要停頓。比如在收集器標(biāo)記垃圾的時(shí)候。但在清除垃圾的時(shí)候,用戶線程可以和GC線程并發(fā)執(zhí)行。Serial收集器 最早的收集器,單線程進(jìn)行GC New和Old Generation都可以使用 在新生代,采用復(fù)制算法;在老生代,采用Mark-Compact算法 因?yàn)槭菃尉€程GC,沒有多線程切換的額外開銷,簡(jiǎn)單實(shí)用 Hotspot Client模式缺省的收集器圖片來(lái)自于深入理解Java虛擬機(jī)-JVM高級(jí)特性與最佳

16、實(shí)踐ParNew收集器 Serial收集器在新生代的多線程版本 使用復(fù)制算法(因?yàn)獒槍?duì)新生代) 只有在多CPU的環(huán)境下,效率才會(huì)比Serial收集器高 可以通過-XX:ParallelGCThreads來(lái)控制GC線程數(shù)的多少。需要結(jié)合具體CPU的個(gè)數(shù) Server模式下新生代的缺省收集器Parallel Scavenge 類似于ParNew,針對(duì)新生代的多線程收集器 使用復(fù)制算法(因?yàn)獒槍?duì)新生代) 區(qū)別于ParNew,更注重吞吐量 可以通過定義參數(shù)來(lái)精確控制吞吐量Parallel Old Parallel Scavenge在老生代的實(shí)現(xiàn) 在JVM 1.6才出現(xiàn)Parallel Old 采用多線

17、程,Mark-Compact算法 更注重吞吐量 Parallel Scavenge + Parallel Old = 高吞吐量,但GC停頓可能不理想圖片來(lái)自于深入理解Java虛擬機(jī)-JVM高級(jí)特性與最佳實(shí)踐CMS收集器(Concurrent Mark-Swap) 追求最短停頓時(shí)間,非常適合Web應(yīng)用 只針對(duì)老年區(qū),一般結(jié)合ParNew使用 Concurrent,GC線程和用戶線程并發(fā)工作(盡量并發(fā)) Mark-Swap 只有在多CPU環(huán)境下才有意義 使用-XX:+UseConcMarkSweepGC打開CMS收集器(Concurrent Mark-Swap) CMS分為4個(gè)步驟: 初始標(biāo)記,并

18、發(fā)標(biāo)記,重新標(biāo)記,并發(fā)清除 初始標(biāo)記和重新標(biāo)記還是會(huì)出現(xiàn)GC停頓,用戶線程需要等待 并發(fā)標(biāo)記和并發(fā)清除不會(huì)出現(xiàn)GC停頓,用戶線程可以繼續(xù)工作。而這兩步是整個(gè)GC最耗費(fèi)時(shí)間的步驟。這樣可以最大程度減少用戶線程的停頓。CMS收集器的缺點(diǎn) CMS以犧牲CPU資源的代價(jià)來(lái)減少用戶線程的停頓。當(dāng)CPU個(gè)數(shù)少于4的時(shí)候,有可能對(duì)吞吐量影響非常大 CMS在并發(fā)清理的過程中,用戶線程還在跑。這時(shí)候需要預(yù)留一部分空間給用戶線程 CMS用Mark-Swap,會(huì)帶來(lái)碎片問題。碎片過多的時(shí)候會(huì)容易頻繁觸發(fā)Full GCG1收集器(Garbage First) Java 7首次正式推出的收集器 目標(biāo)是取代CMS收集器(

19、漫長(zhǎng)的過程) 可控制的GC停頓,通過定義參數(shù)來(lái)控制GC停頓的范圍 解決CMS的碎片問題,用Mark-Compact 關(guān)于G1更詳細(xì)的描述:http:/ JVM喜歡生命周期短的,小的對(duì)象 JVM創(chuàng)建對(duì)象的速度非常高,已經(jīng)非常接近C+ GC回收生命周期短的對(duì)象非常高效 前面提到的新生代復(fù)制算法,對(duì)于生命周期短的對(duì)象,不需要掃描和復(fù)制就能回收編寫GC友好代碼 使用更多生命周期短的、小的、不改變指向(immutable)的對(duì)象 不要害怕創(chuàng)建臨時(shí)對(duì)象作為中間計(jì)算的結(jié)果編寫GC友好代碼 不要濫用對(duì)象池(Object Pool) 出于節(jié)儉的心態(tài),程序員總是傾向于使用對(duì)象池作為緩沖 除非創(chuàng)建對(duì)象的開銷較大,否

20、則對(duì)象池不一定能提高性能,反而會(huì)影響GC效率 比如從數(shù)據(jù)庫(kù)query生成對(duì)象,pooling是有幫助的;但如果不涉及到DB/IO/Network/緊張資源的對(duì)象創(chuàng)建,pooling反而有反效果 對(duì)象池生命周期長(zhǎng),每次full gc都要處理(mark, compact, etc) 如果涉及多線程共享問題,對(duì)象池還可能帶來(lái)同步等額外開銷,得不償失 容易產(chǎn)生內(nèi)存泄漏編寫GC友好代碼 當(dāng)使用Array-based的數(shù)據(jù)結(jié)構(gòu)(ArrayList, HashMap等)時(shí),盡量減少resize 比如new ArrayList時(shí),盡量估算size,在創(chuàng)建的時(shí)候把size確定 減少resize可以避免沒有必要的

21、array copying, gc碎片等問題 如果一個(gè)List只需要順序訪問,不需要隨機(jī)訪問(Random Access),用LinkedList代替ArrayList LinkedList本質(zhì)是鏈表,不需要resize, 但只適用于順序訪問編寫GC友好代碼 避免Java內(nèi)存泄漏 Java內(nèi)存泄漏 VS C/C+內(nèi)存泄漏 C/C+內(nèi)存泄漏:把東西鎖到抽屜里面,但鑰匙丟了 (Object unreachable) Java內(nèi)存泄漏:把有用和沒用的東西都擺滿房間,清潔工(GC)分不清哪些是有用的,哪些是沒用的。沒用的東西沒辦法清理。(Object reachable but unused) Java內(nèi)存泄漏類型 傳統(tǒng)型:Heap越來(lái)越大,直到OOM

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論