最近聽聞不少裁人潮,寒冬潮的消息,因此纔會有下面這些總結,給道友準備,也是爲本身!
但願本身用不到.................java
內存分佈
jvm將內存分爲了堆,方法區,程序計數器,棧(虛擬機棧),本地方法棧5個區域,有些是線程共有的有的是線程共享的。下面就簡單就這幾個區域作簡單說明。算法
程序計數器(PC寄存器)
做用:存儲當前線程正在執行的java方法的JVM指令地址,若是執行的是Native方法,則爲undefined。
每一個線程都有本身的PC寄存器。安全
Java棧(虛擬機棧)
做用:存放方法調用時產生的幀,數據結構是先進後出的棧。
每一次的調用都會產出一個新的幀,方法的執行伴隨着入棧和出棧的操做;該幀存儲java方法的局部變量,操做數棧,常量池指針等。同時內部包含了一個局部變量表。線程私有服務器
本地棧
相似Java棧,只不過是在調用native方法時纔會使用到數據結構
堆
做用:存放Java對象實例,幾乎全部建立的Java對象實例都會被直接分配在堆上,被全部線程共享,能夠在啓動JVM時經過Xmx,Xms等來指定該區域的大小,也是GC工做的主要區域。併發
方法區
做用:存放一些元數據,如類結構信息,常量,靜態變量,常量池也存放於此。在jdk1.7及以前的版本中,將方法區稱爲永久代,而1.8以後去除了永久代,增長了元數據區。方法區也是線程共享的jvm
總結:線程共享的有方法區和堆,線程私有的是程序計數器,Java棧和本地方法棧。性能
GC
垃圾收集的目的是爲了回收那些佔用了內存可是又不會再被使用的對象。線程
基本收集算法
- 引用計數 爲對象添加一個引用計數,用於記錄對象被引用的狀況。若是計數是0,說明沒有對象引用該對象了,能夠被清理;有個問題就是沒法解決循環引用的問題。
- 可達性分析
將對象的引用關係看作是一個圖,將選擇活動中的對象做爲根對象GC Root,而後按圖索驥的去查詢。若是一個對象和GC Root之間不可達,也就是不存在引用鏈,那麼久認爲這個對象時不可達的,能夠被清理。JVM會把Java棧和本地方法棧中正在引用的對象,靜態屬性引用的對象和常量做爲GC Root。
清理算法
- 標記-複製
將內存區域分紅兩塊大小相同的區域(to和from),而後每次都是使用from區域,經過收集算法,將from中還活着的對象遷移到to區域,而且是順序安放,保證內存的連續性,同時將to區域標記爲from區域,原來的from區域標記爲to區域。
- 標記-清除 首先進行標記工做,將要清除的對象進行標記,而後直接進行清除,標記和清除的效率比較高,可是會產生內存碎片化,若是申請大內存,容易引起Full GC,會產生較長時間的STW。
- 標記-整理 相似於標記-清除,可是爲了不內存的碎片化,會在清理過程當中將對象往一個方向移動,保證內存的連續性。
GC執行過程
GC主要發生的區域是在堆區,因此咱們先簡單分析一下堆的結構。借用別人的一張圖: 3d
安裝上圖,從GC年代的角度劃分,java 堆分爲:
- 新生代
新生代是大部分對象的建立和銷燬的區域,所以對新生代也作了劃分:
- Eden區域
Eden會繼續劃分,爲每一個線程劃分一個TLAB區域,爲了安全,會加鎖進行競爭;這些TLAB都是連續分配的,若是一個TLAB滿了,會繼續給當前線程分配新的TLAB。新建立的對象基本都是在當前線程所分配的TLAB中,若是須要建立的對象過大,就會直接分配到老年代。
- Survior區域
Survior會平均大小的分爲兩個區域to和from,而後再GC期間將from和Eden中存活的對象所有遷移到to中,主要是爲了不內存的碎片化。
- 老年代
放置長生命週期的對象(經歷了屢次GC存活的對象),一般是從Survior中拷貝過來的對象。可是,若是新建立的對象在Eden中沒法找到足夠長度的內存,也會直接放到老年代。
堆,新生代,老年代的大小都是能夠經過jvm參數進行設置的。
具體執行過程:
- Java不斷的建立對象,直接分配到Eden區域,若是達到GC設定的閾值,觸發Minor GC。存活下來的會被遷移到Survior中的from區域,同時會對這些對象的生命週期加1,代表存活時間。
- 通過第一次的GC後,Eden會空閒下來,此時繼續在Eden上面分配空間,直到再次達到閾值,觸發GC,此時會在Eden和Survior中的from同時清理,而後將餘下的對象複製到to區域裏面,存活時間加1.
- 屢次發生上述第二步後,當存活對象的存活時間達到閾值時,會發生晉升過程,將達到閾值的對象遷移到老年代。這個閾值也是能夠設置的。一樣,若是Survior大小不夠了也會發生晉升。
- 老年代贊成會進行GC 稱爲Major GC,GC的清理算法根據不一樣的GC類型而不一樣,可是大部分是使用的標記-整理,這樣能夠避免內存的碎片化。
爲了形象借用幾張楊曉峯老師的示意圖:
GC的類別
隨着技術的發展,jvm出現了不少不一樣的垃圾收集器。
- Serial Old GC:串行的,會觸發Stop-The-World,採用標記-整理,用於老年代。
- Serial GC :串行的,複製算法,,會觸發Stop-The-World,適用於單CPU的client環境
- ParNew GC: 並行的,會觸發Stop-The-World,用於新生代,複製算法,適用於多核CPU的Server環境。能夠簡單的理解爲Serial的並行版本。
- Parallel Scavenge GC:並行的,用於新生代,複製算法,能夠控制吞吐量(用戶代碼運行時間/(用戶代碼運行時間+垃圾收集時間)),適用於後臺運算多,交互少的場景。
- CMS(Concurrent Mark Swap) GC: 併發的,標記階段會觸發STW,採用標記-整理算法,用於老年代,適用於服務器
- G1 GC:jdk9 後默認的GC,替代CMS,對於大內存的堆空間,性能會比較優越。
總結一下:
新生代主要會使用的垃圾收集器是Serial,Parallel等 老年代主要是CMS,配合其餘類型一塊兒。