總結:在實際工做中,咱們能夠直接將初始的堆大小與最大堆大小相等,這樣的好處是能夠減小程序運行時垃圾回收次數,從而提升效率。java
-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];
}複製代碼
使用示例: -Xms20m -Xmx20m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC-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 設置最大調用深度
public class JvmDemo04 {
private static int count;
public static void count(){
try {
count++;
count();
} catch (Throwable e) {
System.out.println("最大深度:"+count);
e.printStackTrace();
}
}
public static void 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個步驟,包括:
其中初始標記、從新標記這兩個步驟仍然須要「Stop The World」。初始標記僅僅只是標記一下GC Roots能直接關聯到的對象,速度很快,併發標記階段就是進行GC Roots Tracing的過程,而從新標記階段則是爲了修正併發標記期間,因用戶程序繼續運做而致使標記產生變更的那一部分對象的標記記錄,這個階段的停頓時間通常會比初始標記階段稍長一些,但遠比並發標記的時間短。
因爲整個過程當中耗時最長的併發標記和併發清除過程當中,收集器線程均可以與用戶線程一塊兒工做,因此整體上來講,CMS收集器的內存回收過程是與用戶線程一塊兒併發地執行。老年代收集器(新生代使用ParNew)
優勢:併發收集、低停頓
缺點:產生大量空間碎片、併發階段會下降吞吐量
採用「標記-清除」算法實現,使用多線程的算法去掃描堆,對發現未使用的對象進行回收。
適應場景:大型服務器等。
經過JVM參數 -XX:+UseConcMarkSweepGC設置
在G1中,堆被劃分紅 許多個連續的區域(region)。採用G1算法進行回收,吸取了CMS收集器特色。
特色:支持很大的堆,高吞吐量
實時目標:可配置在N毫秒內最多隻佔用M毫秒的時間進行垃圾回收
經過JVM參數 -XX:+UseG1GC 使用G1垃圾回收器
注意: 併發是指一個處理器同時處理多個任務。
並行是指多個處理器或者是多核的處理器同時處理多個不一樣的任務。
併發是邏輯上的同時發生(simultaneous),而並行是物理上的同時發生。
來個比喻:併發是一我的同時吃三個饅頭,而並行是三我的同時吃三個饅頭。
JMeter是一款在國外很是流行和受歡迎的開源性能測試工具,像LoadRunner 同樣,它也提供了一個利用本地Proxy Server(代理服務器)來錄製生成測試腳本的功能,可是這個功能並很差用。因此在本文中介紹一個更爲經常使用的方法——使用Badboy錄製生成 JMeter 腳本。
簡單的介紹一下Badboy。Badboy是一款不錯的Web自動化測試工具,若是你將它用於非商業用途,或者用於商業用途可是安裝Badboy 的機器數量不超過5臺,你是不須要爲它支付任何費用的。也許是一種推廣策略,Badboy提供了將Web測試腳本直接導出生成JMeter 腳本的功能,而且這個功能很是好用,也很是簡單。你能夠跟着下面的試驗步驟來邁出你在開源世界的第一步。
QPS:Queries Per Second意思是「每秒查詢率」,是一臺服務器每秒可以相應的查詢次數,是對一個特定的查詢服務器在規定時間內所處理流量多少的衡量標準。
-XX:+PrintGCDetails -Xmx32M -Xms1M
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseSerialGC
-XX:PermSize=32M
GC 回收次數25次 吞吐量4662
--> 堆的初始值和堆的最大一致
加大初始堆內存大小-Xms1M 修改成32m
GC 回收次數7次 吞吐量5144複製代碼
-XX:+PrintGCDetails -Xmx512M -Xms32M
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseSerialGC
-XX:PermSize=32M
GC 回收次數6次 吞吐量5141
結論:垃圾回收次數和設置最大堆內存大小無關,只和初始內存有關係。
初始內存會影響吞吐量。複製代碼
-XX:+PrintGCDetails -Xmx512M –Xms512M
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseSerialGC
-XX:PermSize=32M
GC回收次數0次 吞吐量6561次
結論:堆的初始值和最大堆內存一致,而且初始堆越大就會高。複製代碼
-XX:+PrintGCDetails -Xmx512M -Xms512M
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseParNewGC
-XX:PermSize=32M
GC回收0次 吞吐量6800複製代碼
-XX:+PrintGCDetails -Xmx512M -Xms512M
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseConcMarkSweepGC
-XX:PermSize=32M複製代碼
-XX:+PrintGCDetails -Xmx512M -Xms512M
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseG1GC
-XX:PermSize=32M複製代碼
初始堆值和最大堆內存內存越大,吞吐量就越高。
最好使用並行收集器,由於並行收集器速度比串行吞吐量高,速度快。
設置堆內存新生代的比例和老年代的比例最好爲1:2或者1:3。
減小GC對老年代的回收。
我的博客 蝸牛