繼續上次【http://www.javashuo.com/article/p-ctjyidxk-cy.html】的理論繼續。。有點吐血的感受,都不知道學了這麼一大堆理論有何實際意義,自己JVM就是個理論體系比較多的東東,因此理論不得不去面對,繼續硬着頭皮往前進。html
內存結構程序員
![](http://static.javashuo.com/static/loading.gif)
這個在以前的學習中都已經學習過了,複習一下。web
內存分配算法
- 堆上分配
大多數狀況在eden【年輕代中的一個區域】上分配,偶爾會直接在old【老年代】上分配,細節取決於GC的實現。
- 棧上分配
原子類型的局部變量。
內存回收安全
一、GC要作的是將那些dead的對象所佔用的內存回收掉。數據結構
- Hotspot認爲沒有引用的對象是dead的。
- Hotspot將引用分爲四種:Strong【強引用】、Soft【軟引用】、Weak【弱引用】、Phantom【虛引用】,這是大夥熟知的。
一、Strong既默認經過Object o = new Object()這種方式賦值的引用。
二、Soft、Weak、Phantom這三種則是繼續Reference。
二、在Full GC時會對Reference類型的引用進行特殊處理。多線程
- Soft:內存不夠時必定會被GC、長期不用也會被GC。
- Weak:必定會被GC,當被mark爲dead,會在ReferenceQueue中通知。
- Phantom:原本就沒引用,當從jvm heap中釋放時會通知。
以上的概念會在將來舉例進行代碼說明的,先有個印象。併發
垃圾收集算法dom
![](http://static.javashuo.com/static/loading.gif)
以上是一些比較經典的垃圾收集算法,下面會逐個進行說明。jvm
GC的時機
一、在分代模型的基礎上,GC從時機上分爲兩種:Scavenge GC和Full GC。
二、Scavenge GC(Minor GC)
- 觸發時機:新對象生成時,Eden空間滿了。
- 理論上Eden區大多數對象會在Scavenge GC回收,複製算法的執行效率會很高,Scavenge GC時間比較短。
三、Full GC【這個在實際中必定得要避免】
- 對整個JVM進行整理,包括Young、Old和Perm。
- 主要的觸發時機:1)Old滿了;2)Perm滿了;3)system.gc()
- 效率很低,儘可能減小Full GC。
垃圾回收器(Garbage Collector)
- 分代模型:GC的宏觀願景。
- 垃圾回收器:GC的具體實現。
- Hotspot JVM提供多種垃圾回收器,咱們須要根據具體應用的須要採用不一樣的回收器。
- 沒有萬能的垃圾回收器,每種垃圾回收器都有本身的適用場景。
垃圾收集器的「並行」和「併發」
- 並行(Parallel):指多個收集器的線程同時工做,可是用戶線程處於等待狀態。
- 併發(Concurrent):指收集器在工做時同時,能夠容許用戶線程工做。
併發不表明解決了GC停頓的問題,在關鍵的步驟仍是要停頓。好比在收集器標記垃圾的時候。但在清除垃圾的時候,用戶線程能夠和GC線程併發執行。
Serial收集器
ParNew收集器
- ParNew收集器就是Serial的多線程版本,除了使用多個收集線程外,其他行爲包括算法、STW、對象分配規則、回收策略等都與Serial收集器如出一轍。
- 對應的這種收集器是虛擬機運行在Server模式的默認新生代收集器,在單CPU的環境中,ParNew收集器並不會比Serial收集器有更好的效果。
- Serial收集器在新生代的多線程版本。
- 使用複製算法(由於針對新生代)。
- 只有在多CPU的環境下,效率纔會比Serial收集器高。
- 能夠經過-XX:ParallelGCThreads來控制GC線程數的多少。須要結合具體CPU的個數。
- Server模式下新生代的缺省收集器。
Parallel Scavenge收集器
- Parallel Scavenge收集器也是一個多線程收集器,也是使用複製算法,但它的對象分配規則與回收策略都與ParNew收集器有所不一樣,它是以吞吐量最大化(既GC時間佔總運行時間最小)爲目標的收集器實現,它容許較長時間的STW換取總吞吐量最大化。
Serial Old收集器
- Serial Old是單線程收集器,使用標記-整理算法,是老年代的收集器。
Parallel Old收集器
- 老年代版本吞吐量優先收集器,使用多線程和標記一整理算法,JVM1.6提供,在此以前,新生代使用了PS收集器的話,老年代除Serial Old外別無選擇,由於PS沒法與CMS收集器配合工做。【瞭解既可】
- Parallel Scavenge在老年代的實現
- 在JVM1.6纔出現Parallel Old
- 採用多線程,Mark-Compact算法
- 更注重吞吐量
- Parallel Scavenge + Parallel Old = 高吞吐量,但GC停頓可能不理想
![](http://static.javashuo.com/static/loading.gif)
CMS(Concurrent Mark Sweep)收集器【特別複雜的一種收集器】
- CMS是一種以最短停頓時間爲目標的收集器,使用CMS並不能達到GC效率最高(整體GC時間最小),但它能儘量下降GC時服務的停頓時間,CMS收集器使用的是標記-清除算法。
- 追求最短停頓時間,很是適合Web應用。
- 只針對老年區,通常結合ParNew使用。
- Concurrent,GC線程和用戶線程併發工做(儘可能併發)。
- Mark-Sweep。
- 只有在多CPU環境下才有意義 。
- 使用-XX:+UseConcMarkSweepGC打開。
- CMS以犧牲CPU資源的代價來減小用戶線程的停頓。當CPU個數少於4的時候,有可能對吞吐量影響很是大。
- CMS在併發清理的過程當中,用戶線程還在跑。這時候須要預留一部分空間給用戶線程。
- CMS用Mark-Sweep,會帶來碎片問題。碎片過多的時候會容易頻繁觸發Full GC。
GC垃圾收集器的JVM參數定義
![](http://static.javashuo.com/static/loading.gif)
Java內存泄漏的經典緣由
一、對象定義在錯誤的範圍(Wrong Scope)。
二、異常(Exception)處理不當。
- 錯誤的作法
![](http://static.javashuo.com/static/loading.gif)
對於有經驗的程序員應該不會出現上面的問題,可是這裏只是拋出泄漏的場景。
- 正確的作法
![](http://static.javashuo.com/static/loading.gif)
三、集合數據管理不當。
- 當使用Array-based的數據結構(ArrayList,HashMap等)時,儘可能減小resize:
a、好比new ArrayList時,儘可能估算size,在建立的時候把size肯定。
b、減小resize能夠避免沒有必要的array copying,gc碎片等問題。
- 若是一個List只須要順序訪問,不須要隨機訪問(Random Access),用LinkedList代替ArrayList
a、LInkedList本質是鏈表,不須要resize,但只適用於順序訪問。
以上是對JVM垃圾回收相關理論的總體瞭解,說實話看完其實頭暈暈的,不要緊,接下來則會用實踐來反證理論。