一、jvm內存調優 (Gc 和 Full gc)
hotspot
-Xms40m 最小堆內存
-Xmx512m 最大值內存
-verboose:gc
-XX:PrintGCDetails
-XX:printGCDateStamps
-Xloggc:D:/gc/gc.log
調優主要調到Gc [PSYoungGen: 10752k->1530k(12288k)] 不出現即可。
PSYoungGen : Young 年輕
Prallel Scavenge: 年輕代並行收集器
10752k -->1530k(12288k)
當前年輕代大小 --->gc之后年輕代大小 (年輕代總的分配的空間)
10752中-->2543k(39936k)
堆內存
調優工具:Eclipse軟件
#jvm內存調優參數 (備注:調優gc )
用編輯器打開:eclipse.ini 文件
-Xms512m #堆的大小,默認512m
-Xmx512m #堆的大小,默認512m
-XX:NewSize=400m #年輕代大小
-XX:MaxNewSize=400m #年輕代大小
-XX:PermSize=90m #永久代大小
-XX:MaxPermSize=90m #永久代大小
查看日志: gc.log
2017-02-22To0:57:18.252+0800 : 9.149: 【Full GC [PSYoungGen: 1521k ->0k(23040k)]】....后面省略。
Linux系統中,安裝好tomcat,
#配置文件路徑 [root@nulige bin]# cd /application/tomcat/bin [root@nulige bin]# ll total 788 -rw-r--r-- 1 root root 28393 Sep 28 2015 bootstrap.jar -rw-r--r-- 1 root root 13825 Sep 28 2015 catalina.bat -rwxr-xr-x 1 root root 21389 Sep 28 2015 catalina.sh -rw-r--r-- 1 root root 1647 Sep 28 2015 catalina-tasks.xml -rw-r--r-- 1 root root 24283 Sep 28 2015 commons-daemon.jar -rw-r--r-- 1 root root 204944 Sep 28 2015 commons-daemon-native.tar.gz -rw-r--r-- 1 root root 2040 Sep 28 2015 configtest.bat -rwxr-xr-x 1 root root 1922 Sep 28 2015 configtest.sh -rwxr-xr-x 1 root root 7888 Sep 28 2015 daemon.sh -rw-r--r-- 1 root root 2091 Sep 28 2015 digest.bat -rwxr-xr-x 1 root root 1965 Sep 28 2015 digest.sh -rw-r--r-- 1 root root 3430 Sep 28 2015 setclasspath.bat -rwxr-xr-x 1 root root 3547 Sep 28 2015 setclasspath.sh -rw-r--r-- 1 root root 2020 Sep 28 2015 shutdown.bat -rwxr-xr-x 1 root root 1902 Sep 28 2015 shutdown.sh -rw-r--r-- 1 root root 2022 Sep 28 2015 startup.bat -rwxr-xr-x 1 root root 1904 Sep 28 2015 startup.sh -rw-r--r-- 1 root root 40882 Sep 28 2015 tomcat-juli.jar -rw-r--r-- 1 root root 388787 Sep 28 2015 tomcat-native.tar.gz -rw-r--r-- 1 root root 4057 Sep 28 2015 tool-wrapper.bat -rwxr-xr-x 1 root root 5061 Sep 28 2015 tool-wrapper.sh -rw-r--r-- 1 root root 2026 Sep 28 2015 version.bat -rwxr-xr-x 1 root root 1908 Sep 28 2015 version.sh
#調優參數 (備注:根據服務器硬件配置,進行調優)
優化catalina.sh配置文件。在catalina.sh配置文件中添加以下代碼: JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms1024m -Xmx1024m -XX:NewSize=512m -XX:MaxNewSize=512m -XX:PermSize=512m -XX:MaxPermSize=512m" server:一定要作為第一個參數,在多個CPU時性能佳 -Xms:初始堆內存Heap大小,使用的最小內存,cpu性能高時此值應設的大一些 -Xmx:初始堆內存heap最大值,使用的最大內存 上面兩個值是分配JVM的最小和最大內存,取決於硬件物理內存的大小,建議均設為物理內存的一半。 -XX:PermSize:設定內存的永久保存區域 -XX:MaxPermSize:設定最大內存的永久保存區域 -XX:MaxNewSize: -Xss 15120 這使得JBoss每增加一個線程(thread)就會立即消耗15M內存,而最佳值應該是128K,默認值好像是512k. +XX:AggressiveHeap 會使得 Xms沒有意義。這個參數讓jvm忽略Xmx參數,瘋狂地吃完一個G物理內存,再吃盡一個G的swap。 -Xss:每個線程的Stack大小 -verbose:gc 現實垃圾收集信息 -Xloggc:gc.log 指定垃圾收集日志文件 -Xmn:young generation的heap大小,一般設置為Xmx的3、4分之一 -XX:+UseParNewGC :縮短minor收集的時間 -XX:+UseConcMarkSweepGC :縮短major收集的時間
二、垃圾回收機制處法
2.1、標記清除算法
標記-清除(Mark-Sweep)算法是最基礎的算法,就如它的名字一樣,算法分為”標記”和”清除”兩個階段:首先標記出所有需要回收的對象,在標記完成后統一回收掉所有被標記的對象。之所以說它是最基礎的收集算法,是因為后續的收集算法都是基於這種思路並對其缺點進行改進而得到的。它主要有兩個缺點:一個是效率問題,標記和清楚過程的效率都不高;另外一個是空間問題,標記清楚后會產生大量不連續的內存碎片,空間碎片太多可能會導致,當程序在以后的運行過程中需要分配較大對象時無法找到足夠連續的內存空間而不得不提前出發另一次垃圾收集動作。
內存會產生碎片,導致沒有空間來分配,會發生Full GC,導致進程會停頓。
2.2、復制算法
內存划分成兩塊,會先使用一塊,用完后,就會放到保留區,再把原來的空間一次性清理掉。(實際分配比例,不是按一比一分配的,新生代>老年代。)
為了解決效率問題,一種稱為復制(Copying)的收集算法就出現了,它將可用內存按容量划分為大小相等的兩塊,每次只是用其中一塊。當這一塊的內存用完了,就將還存活着的對象復制到另外一塊上面,然后再把已使用過的內存空間一次清理掉。這樣使得每次都是對其中的一塊進行內存回收,沒存分配時也就不用考慮內存碎片等復雜情況,只要移動堆頂指針,按順序分配內存即可,實現簡單,運行高效。只是這種算法的代價是將員村縮小為原來的一半,未免太高了一點。
優點:解決內存碎片的問題。
缺點:例如:64G內存,只使用其中一半。
2.3、標記整理算法
標記-整理(Mark-Compact)算法不直接對可回收對象進行清理,而是讓所有可用的對象都向一端移動。然后直接清理掉邊界意外的內存。
復制手機算法在對象存活率較高時就要執行較多的復制操作,效率將會貶低。更關鍵的是,如果不想浪費50%的空間,就需要有額外的空間進行分配擔保,以應對被使用的內存中所有對象都100%存活的極端情況,所以在老年代一般不能直接選用這種算法。
根據老年代的特點,有人提出了另外一種”標記-整理”算法,標記過程仍然與標記-清楚算法一樣,但是后續步驟不是直接對可回收對象進行清理,而是讓所有存活的對象都向一端移動,然后直接清理掉端邊界意外的內存。
2.4、分代收集算法
當前商業虛擬機的垃圾收集都采用分代收集(Generational Collection)算法,這種算法並沒有什么新的思想,只是根據對象的存貨周期的不同將內存划分為幾塊。一般是把Java堆分成新生代和老年代,這樣就可以根據各個年代的特點采用最適當的手機算法。在新生代中,每次垃圾收集時都發現有大批對象死去,只有少量存活,那么就選用復制算法,只需要付出少量存活對象的復制成本就可以完成收集。而老年代中因為對象存活率高、沒有額外空間對它進行分配擔保,就必須使用標記-清理或標記-整理算法來進行回收
三、垃圾收集器
3.1、Serial : 串行收集器 (備注:單核cpu,單線程收集),屬於新生代收集器
Serial收集器是JAVA虛擬機中最基本、歷史最悠久的收集器,在JDK 1.3.1之前是JAVA虛擬機新生代收集的唯一選擇。Serial收集器是一個單線程的收集器,但它的“單線程”的意義並不僅僅是說明它只會使用一個CPU或一條收集線程去完成垃圾收集工作,更重要的是在它進行垃圾收集時,必須暫停其他所有的工作線程,直到它收集結束。
要是服務器每運行一個小時就會暫停5分鍾,老板會有什么樣的心情?
3.2、ParNew: 並行收集器 (備注:多線程同時收集) ,屬於新生代收集器
ParNew收集器是JAVA虛擬機中垃圾收集器的一種。它是Serial收集器的多線程版本,除了使用多條線程進行垃圾收集之外,其余行為包括Serial收集器可用的所有控制參數(例如:-XX:SurvivorRatio、-XX:PretenureSizeThreshold、-XX:HandlePromotionFailure等)、收集算法、Stop The World、對象分配規則、回收策略等都與Serial收集器一致。
3.3、Parallel scavenge: 並行收集器,屬於新生代收集器
Parallel Scavenge收集器的關注點與其他收集器不同, ParallelScavenge收集器的目標則是達到一個可控制的吞吐量(Throughput)。所謂吞吐量就是CPU用於運行用戶代碼的時間與CPU總消耗時間的比值,即吞吐量 = 運行用戶代碼時間 /(運行用戶代碼時間 + 垃圾收集時間),虛擬機總共運行了100分鍾,其中垃圾收集花掉1分鍾,那吞吐量就是99%。
由於與吞吐量關系密切,Parallel Scavenge收集器也經常被稱為“吞吐量優先”收集器。
該垃圾收集器,是JAVA虛擬機在Server模式下的默認值,使用Server模式后,java虛擬機使用Parallel Scavenge收集器(新生代)+ Serial Old收集器(老年代)的收集器組合進行內存回收。
3.4、Serial old: 老年代
3.5、Parallel old: 老年代,多線程,並行處理
3.6、CMS concurrent Nark Sweep 並發標記整理 (備注:老年代中用得最多的收集器)
並發標記清理(Concurrent Mark Sweep,CMS)收集器也稱為並發低停頓收集器(Concurrent Low Pause Collector)或低延遲(low-latency)垃圾收集器;
在前面ParNew收集器曾簡單介紹過其特點;
針對老年代;
基於"標記-清除"算法(不進行壓縮操作,產生內存碎片);
以獲取最短回收停頓時間為目標;
並發收集、低停頓;
需要更多的內存(看后面的缺點);
3.7、G1
整堆收集器:G1,不會產生碎片
(A)、並行與並發
能充分利用多CPU、多核環境下的硬件優勢;
可以並行來縮短"Stop The World"停頓時間;
也可以並發讓垃圾收集與用戶程序同時進行;
(B)、分代收集,收集范圍包括新生代和老年代
能獨立管理整個GC堆(新生代和老年代),而不需要與其他收集器搭配;
能夠采用不同方式處理不同時期的對象;
雖然保留分代概念,但Java堆的內存布局有很大差別;
將整個堆划分為多個大小相等的獨立區域(Region);
新生代和老年代不再是物理隔離,它們都是一部分Region(不需要連續)的集合;
四、使用方法
看應用場景:
單核cpu: 使用GMS + Serial
多核cpu: 使用GMS + ParNew
Serialold + Serial /Parallel scavenge /ParNew
Parallel old + Parallel scavenge
Eden from survivor to survivor
五、其它
Java虛擬機垃圾回收, 7種垃圾收集器 。
參考:https://blog.csdn.net/tjiyu/article/details/53983650
視頻學習地址:https://v.qq.com/x/page/s0379plgejm.html