1、內存分佈web
Java虛擬機所管理的內存將會包括如下幾個運行時數據區域,以下圖所示:算法
本地方法棧數組
本地方法棧(Native Method Stacks)與虛擬機棧所發揮的做用是很是類似的,其區別不過是虛擬機棧爲虛擬機執行Java方法(也就是字節碼)服務,而本地方法棧則是爲虛擬機使用到的Native方法服務。虛擬機規範中對本地方法棧中的方法使用的語言、使用方式與數據結構並無強制規定,所以具體的虛擬機能夠自由實現它。甚至有的虛擬機(譬如Sun HotSpot虛擬機)直接就把本地方法棧和虛擬機棧合二爲一。與緩存
虛擬機棧同樣,本地方法棧區域也會拋出StackOverflowError和OutOfMemoryError異常。安全
(我的理解:虛擬機棧就是一般所說的棧,本地方法棧服務於native方法)數據結構
運行時常量池併發
運行時常量池(Runtime Constant Pool)是方法區的一部分。Class文件中除了有類的版本、字段、方法、接口等描述等信息外,還有一項信息是常量池(Constant Pool Table),用於存放編譯期生成的各類字面量和符號引用,這部份內容將在類加載後存放到方法區的運行時常量池中。框架
直接內存(Direct Memory)jvm
直接內存並非JVM管理的內存,但這部份內存常常被使用,也可能致使OutOfMemoryError異常。函數
JDK中有一種基於通道(Channel)和緩衝區(Buffer)的I/O方式,將由C語言實現的native函數庫直接分配堆外內存,用存儲在JVM堆中的DirectByteBuffer來引用。因爲直接內存收到本機器內存的限制,因此也可能出現OutOfMemoryError的異常。
2、須要回收的區域和對象
回收區域:堆和方法區
如何判斷一個對象已死(便可回收對象),通常有引用計數算法和可達性分析算法
一、引用計數算法:每一個對象都有一個引用計數器,每當有一個地方引用它時計數器就加1,引用失效時計數器就減1,當計數器爲0時,該對象就能夠回收。缺點是循環引用對象不能被回收。
二、可達性分析算法:一系列「GC ROOTs」的對象做爲起點,當某個對象與GC ROOTS不可達時,該對象即被判斷爲可回收對象。能夠做爲GC ROOTs對象的有如下幾種:
三、擴充的引用
引用分爲四種:(不會被回收的,可回收也可不回收,確定會被回收、不須要理會的)
a> 強引用(Strong Reference).就是爲剛被new出來的對象所加的引用,它的特色就是,永遠不會被回收。
b> 軟引用(Soft Reference).聲明爲軟引用的類,是可被回收的對象,若是JVM內存並不緊張,這類對象能夠不被回收,若是內存緊張,則會被回收。此處有一個問題,既然被引用爲軟引用的對象能夠回收,爲何不去回收呢?其實咱們知道,Java中是存在緩存機制的,就拿字面量緩存來講,有些時候,緩存的對象就是當前無關緊要的,只是留在內存中若是還有須要,則不須要從新分配內存便可使用,所以,這些對象便可被引用爲軟引用,方便使用,提升程序性能。
c> 弱引用(Weak Reference).弱引用的對象就是必定須要進行垃圾回收的,無論內存是否緊張,當進行GC時,標記爲弱引用的對象必定會被清理回收。
d> 虛引用(Phantom Reference).虛引用弱的能夠忽略不計,JVM徹底不會在意虛引用,其惟一做用對象被回收時會收到一些通知。
四、對象回收處理過程
對象被回收前須要進行兩次標記過程。第一次是對象與GC Roots間不可達,即被第一次標記而且篩選該對象是否有必要執行finalize()方法,將篩選的對象放到一個執行隊列中,沒有必要執行finalize方法的對象會被回收;第二次僅對隊列中的對象進行標記,若是在執行finalize方法中將對象與GC ROOTS關聯上,則該對象將不會被回收,不然該對象將被回收。
3、內存分配
Java內存分配和回收的機制歸納的說,就是:分代分配,分代回收。對象將根據存活的時間被分爲:年輕代(Young Generation)、年老代(Old Generation)、永久代(Permanent Generation,也就是方法區)
年輕代(Young Generation):對象被建立時,內存的分配首先發生在年輕代(大對象能夠直接 被建立在年老代),大部分的對象在建立後很快就再也不使用,所以很快變得不可達,因而被年輕代的GC機制清理掉(IBM的研究代表,98%的對象都是很快消 亡的),這個GC機制被稱爲Minor GC或叫Young GC。注意,Minor GC並不表明年輕代內存不足,它事實上只表示在Eden區上的GC。
年輕代上的內存分配是這樣的,年輕代能夠分爲3個區域:Eden區(伊甸園,亞當和夏娃偷吃禁果生娃娃的地方,用來表示內存首次分配的區域,再 貼切不過)和兩個存活區(Survivor 0 、Survivor 1)。內存分配過程爲:
年老代(Old Generation):對象若是在年輕代存活了足夠長的時間而沒有被清理掉(即在幾回 Young GC後存活了下來),則會被複制到年老代,年老代的空間通常比年輕代大,能存放更多的對象,在年老代上發生的GC次數也比年輕代少。當年老代內存不足時, 將執行Major GC,也叫 Full GC。
4、垃圾收集算法
一、標記-清除算法
分兩個階段,標記階段和清除階段。首選標記出全部須要回收的對象,標記完成後統一回收全部被標記的對象。
二、複製算法
將內存分爲大小相等的兩塊,每次只使用其中一塊。當一塊內存用完了,就將活着的對象複製到另外一塊上面,最後一次性清除已使用過的內存空間。(通常新生代採用這種算法)
三、標記-整理算法
也是分爲兩個階段。第一個階段是標記,第二個階段是將全部存活對象移動到一端,而後直接清理掉邊界之外的內存。
四、分代收集算法
根據對象存活時間不一樣將內存分爲幾部分。通常將堆分爲新生代和年老代,根據年代的特色採用最適合的收集算法。例如,新生代通常採用複製算法,年老代採用標記-清除或者標記-整理算法。
5、JVM經常使用內存參數設置
a: -Xmx<n>
指定 jvm 的最大 heap 大小 , 如 :-Xmx=2g
b: -Xms<n>
指定 jvm 的最小 heap 大小 , 如 :-Xms=2g , 高併發應用, 建議和-Xmx同樣, 防止由於內存收縮/忽然增大帶來的性能影響。
c: -Xmn<n>
指定 jvm 中 New Generation 的大小 , 如 :-Xmn256m。 這個參數很影響性能, 若是你的程序須要比較多的臨時內存,建議設置到512M, 若是用的少, 儘可能下降這個數值, 通常來講128/256足以使用了。
d: -XX:PermSize=<n>
指定 jvm 中 Perm Generation 的最小值 , 如 :-XX:PermSize=32m。 這個參數須要看你的實際狀況,。能夠經過jmap 命令看看到底須要多少。
e: -XX:MaxPermSize=<n>
指定 Perm Generation 的最大值 , 如 :-XX:MaxPermSize=64m
f: -Xss<n>
指定線程桟大小 , 如 :-Xss128k, 通常來講,webx框架下的應用須要256K。 若是你的程序有大規模的遞歸行爲,請考慮設置到512K/1M。 這個須要全面的測試才能知道。 不過,256K已經很大了。 這個參數對性能的影響比較大的。
g: -XX:NewRatio=<n>
指定 jvm 中 Old Generation heap size 與 New Generation 的比例 , 在使用 CMS GC 的狀況下此參數失效 , 如 :-XX:NewRatio=2
h: -XX:SurvivorRatio=<n>
指 定 New Generation 中 Eden Space 與一個 Survivor Space 的 heap size 比例 ,-XX:SurvivorRatio=8, 那麼在總共 New Generation 爲 10m 的狀況下 ,Eden Space 爲 8m
i: -XX:MinHeapFreeRatio=<n>
指定 jvm heap 在使用率小於 n 的狀況下 ,heap 進行收縮 ,Xmx==Xms 的狀況下無效 , 如 :-XX:MinHeapFreeRatio=30
j: -XX:MaxHeapFreeRatio=<n>
指定 jvm heap 在使用率大於 n 的狀況下 ,heap 進行擴張 ,Xmx==Xms 的狀況下無效 , 如 :-XX:MaxHeapFreeRatio=70
k: -XX:LargePageSizeInBytes=<n>
指定 Java heap 的分頁頁面大小 , 如 :-XX:LargePageSizeInBytes=128m
6、內存分配與回收策略
對象優先在Eden分配;
大對象直接進入老年代;(例如:長字符串和數組)
長期存活的對象將進入老年代;(Survivor空間中通過必定次數minor GC仍舊存活的對象)
動態對象年齡斷定;(Survivor空間中對象不必定非等到必定年齡才能移動到年老代,也能夠經過相同年齡對象總大小大於Survivor空間的一半,該年齡及以上大小的對象都被移動到年老代)
空間分配擔保;(根據年老代上的最大可用連續空間是否大於整個新生代對象的空間,若是大於能夠確保是安全的,能夠直接minor GC;若是不是根據狀況選擇minor GC仍是full GC)