-XX:+PrintGC 每次觸發GC的時候打印相關日誌java
-XX:+UseSerialGC 串行回收算法
-XX:+PrintGCDetails 更詳細的GC日誌數組
-Xms 堆初始值服務器
-Xmx 堆最大可用值多線程
-Xmn 新生代堆最大可用值併發
-XX:SurvivorRatio 用來設置新生代中eden空間和from/to空間的比例.工具
-XX:NewRatio 配置新生代與老年代佔比 1:2性能
含以-XX:SurvivorRatio=eden/from=den/to測試
總結:在實際工做中,咱們能夠直接將初始的堆大小與最大堆大小相等,網站
這樣的好處是能夠減小程序運行時垃圾回收次數,從而提升效率。
-XX:SurvivorRatio 用來設置新生代中eden空間和from/to空間的比例.
使用示例: -Xmx20m -Xms5m
說明: 當下Java應用最大可用內存爲20M, 初始內存爲5M
// byte[] b = new byte[4 * 1024 * 1024]; // System.out.println("分配了4M空間給數組"); System.out.print("最大內存"); System.out.println(Runtime.getRuntime().maxMemory() / 1024.0 / 1024 + "M"); System.out.print("可用內存"); System.out.println(Runtime.getRuntime().freeMemory() / 1024.0 / 1024 + "M"); System.out.print("已經使用內存"); System.out.println(Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M");
使用示例:-Xms20m -Xmx20m -Xmn1m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC
說明:堆內存初始化值20m,堆內存最大值20m,新生代最大值可用1m,eden空間和from/to空間的比例爲2/1
byte[] b = null; for (int i = 0; i < 10; i++) { b = new byte[1 * 1024 * 1024]; }
-XX:NewRatio=2
說明:堆內存初始化值20m,堆內存最大值20m,新生代最大值可用1m,eden空間和from/to空間的比例爲2/1
新生代和老年代的佔比爲1/2
錯誤緣由: java.lang.OutOfMemoryError: Java heap space 堆內存溢出
解決辦法:設置堆內存大小 // -Xms1m -Xmx10m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
// -Xms1m -Xmx10m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError List<Object> listObject = new ArrayList<>(); for (int i = 0; i < 10; i++) { System.out.println("i:" + i); Byte[] bytes = new Byte[1 * 1024 * 1024]; listObject.add(bytes); } System.out.println("添加成功...");
虛擬機棧溢出
錯誤緣由: java.lang.StackOverflowError 棧內存溢出
棧溢出 產生於遞歸調用,循環遍歷是不會的,可是循環方法裏面產生遞歸調用, 也會發生棧溢出。
解決辦法:設置線程最大調用深度
-Xss5m 設置最大調用深度
publicclass JvmDemo04 { privatestaticintcount; publicstaticvoid count(){ try { count++; count(); } catch (Throwable e) { System.out.println("最大深度:"+count); e.printStackTrace(); } } publicstaticvoid main(String[] args) { count(); } }
Java內存泄漏就是沒有及時清理內存垃圾,致使系統沒法再給你提供內存資源(內存資源耗盡);
而Java內存溢出就是你要求分配的內存超出了系統能給你的,系統不能知足需求,因而產生溢出。
內存溢出,這個好理解,說明存儲空間不夠大。就像倒水倒多了,從杯子上面溢出了來了同樣。
內存泄漏,原理是,使用過的內存空間沒有被及時釋放,長時間佔用內存,最終致使內存空間不足,而出現內存溢出。
串行回收: JDK1.5前的默認算法 缺點是隻有一個線程,執行垃圾回收時程序中止的時間比較長
並行回收: 多個線程執行垃圾回收適合於吞吐量的系統,回收時系統會中止運行
串行收集器是最古老,最穩定以及效率高的收集器,可能會產生較長的停頓,只使用一個線程去回收。新生代、老年代使用串行回收;新生代複製算法、老年代標記-壓縮;垃圾收集的過程當中會Stop The World(服務暫停)
一個單線程的收集器,在進行垃圾收集時候,必須暫停其餘全部的工做線程直到它收集結束。
特色:CPU利用率最高,停頓時間即用戶等待時間比較長。
適用場景:小型應用
經過JVM參數-XX:+UseSerialGC可使用串行垃圾回收器。
ParNew收集器其實就是Serial收集器的多線程版本。新生代並行,老年代串行;新生代複製算法、老年代標記-壓縮
參數控制:-XX:+UseParNewGC ParNew收集器
-XX:ParallelGCThreads 限制線程數量
Parallel Scavenge收集器相似ParNew收集器,Parallel收集器更關注系統的吞吐量。能夠經過參數來打開自適應調節策略,虛擬機會根據當前系統的運行狀況收集性能監控信息,動態調整這些參數以提供最合適的停頓時間或最大的吞吐量;也能夠經過參數控制GC的時間不大於多少毫秒或者比例;新生代複製算法、老年代標記-壓縮
採用多線程來經過掃描並壓縮堆
特色:停頓時間短,回收效率高,對吞吐量要求高。
適用場景:大型應用,科學計算,大規模數據採集等。
經過JVM參數 XX:+USeParNewGC 打開併發標記掃描垃圾回收器。
CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間爲目標的收集器。目前很大一部分的Java應用都集中在互聯網站或B/S系統的服務端上,這類應用尤爲重視服務的響應速度,但願系統停頓時間最短,以給用戶帶來較好的體驗。
從名字(包含「Mark Sweep」)上就能夠看出CMS收集器是基於「標記-清除」算法實現的,它的運做過程相對於前面幾種收集器來講要更復雜一些,整個過程分爲4個步驟,包括:
初始標記(CMS initial mark)
併發標記(CMS concurrent mark)
從新標記(CMS remark)
併發清除(CMS concurrent sweep)
其中初始標記、從新標記這兩個步驟仍然須要「Stop The World」。初始標記僅僅只是標記一下GC Roots能直接關聯到的對象,速度很快,併發標記階段就是進行GC Roots Tracing的過程,而從新標記階段則是爲了修正併發標記期間,因用戶程序繼續運做而致使標記產生變更的那一部分對象的標記記錄,這個階段的停頓時間通常會比初始標記階段稍長一些,但遠比並發標記的時間短。
因爲整個過程當中耗時最長的併發標記和併發清除過程當中,收集器線程均可以與用戶線程一塊兒工做,因此整體上來講,CMS收集器的內存回收過程是與用戶線程一塊兒併發地執行。老年代收集器(新生代使用ParNew)
優勢:併發收集、低停頓
缺點:產生大量空間碎片、併發階段會下降吞吐量
採用「標記-清除」算法實現,使用多線程的算法去掃描堆,對發現未使用的對象進行回收。
(1)初始標記
(2)併發標記
(3)併發預處理
(4)從新標記
(5)併發清除
(6)併發重置
特色:響應時間優先,減小垃圾收集停頓時間
適應場景:大型服務器等。
經過JVM參數 -XX:+UseConcMarkSweepGC設置
在G1中,堆被劃分紅 許多個連續的區域(region)。採用G1算法進行回收,吸取了CMS收集器特色。
特色:支持很大的堆,高吞吐量
--支持多CPU和垃圾回收線程
--在主線程暫停的狀況下,使用並行收集
--在主線程運行的狀況下,使用併發收集
實時目標:可配置在N毫秒內最多隻佔用M毫秒的時間進行垃圾回收
經過JVM參數 -XX:+UseG1GC 使用G1垃圾回收器
注意: 併發是指一個處理器同時處理多個任務。
並行是指多個處理器或者是多核的處理器同時處理多個不一樣的任務。
併發是邏輯上的同時發生(simultaneous),而並行是物理上的同時發生。
來個比喻:併發是一我的同時吃三個饅頭,而並行是三我的同時吃三個饅頭。
初始堆值和最大堆內存內存越大,吞吐量就越高。
最好使用並行收集器,由於並行收集器速度比串行吞吐量高,速度快。
設置堆內存新生代的比例和老年代的比例最好爲1:2或者1:3。
減小GC對老年代的回收。