1、調優目的
減少GC的頻率和Full GC的次數
2、調優方法
使用jmap、mat等工具進行堆使用情況分析,內存等分析,通過調優參數重複分析使用情況,直到參數最優。
3、工具的使用
(1)jmap
觀察運行中的jvm物理內存的佔用情況。
參數如下:
-heap :打印jvm heap的情況,會列出堆的總體使用情況,還有新生代老生代的內存佔用情況。
-histo: 打印jvm heap的直方圖。其輸出信息包括類名,對象數量,對象佔用大小。
-histo:live : 同上,但是隻答應存活對象的情況
-permstat: 打印permanent generation heap情況
命令使用:
jmap -heap 32575
可以觀察到New Generation(Eden Space,From Space,To Space),tenured generation,Perm Generation的內存使用情況
jmap -histo 32575| jmap -histo:live 32575
可以觀察heap中所有對象的情況(heap中所有生存的對象的情況)。包括對象數量和所佔空間大小。
輸出內容:
寫個腳本,可以很快把佔用heap最大的對象找出來,對付內存泄漏特別有效。
如果結果很多,可以用以下命令輸出到文本文件。
jmap -histo 32575| jmap -histo:live 32575> a.txt
jmap是一個可以輸出所有內存中對象的工具,甚至可以將VM 中的heap,以二進制輸出成文本。
命令:jmap -dump:format=b,file=heap.bin
file:保存路徑及文件名
pid:進程編號
(2)jinfo:可以輸出並修改運行時的java 進程的opts。
jinfo:的用處比較簡單,就是能輸出並修改運行時的java進程的運行參數。用法是jinfo -opt pid 如:查看2788的MaxPerm大小可以用 jinfo -flag MaxPermSize 2788。
(3) jps:與unix上的ps類似,用來顯示本地的java進程,可以查看本地運行着幾個java程序,並顯示他們的進程號。
(4) jstat:一個極強的監視VM內存工具。可以用來監視VM內存內的各種堆和非堆的大小及其內存使用量。
jstat工具特別強大,有衆多的可選項,詳細查看堆內各個部分的使用量,以及加載類的數量。使用時,需加上查看進程的進程id,和所選參數。以下詳細介紹各個參數的意義。
jstat -class pid:顯示加載class的數量,及所佔空間等信息。第一列是加載類數量。
jstat -compiler pid:顯示VM實時編譯的數量等信息。
jstat -gc pid:可以顯示gc的信息,查看gc的次數,及時間。其中最後五項,分別是young gc的次數,young gc的時間,full gc的次數,full gc的時間,gc的總時間。
jstat -gccapacity:可以顯示,VM內存中三代(young,old,perm)對象的使用和佔用大小,如:PGCMN顯示的是最小perm的內存使用量,PGCMX顯示的是perm的內存最大使用量,PGC是當前新生成的perm內存佔用量,PC是但前perm內存佔用量。其他的可以根據這個類推, OC是old內純的佔用量。
jstat -gcnew pid:new對象的信息。
jstat -gcnewcapacity pid:new對象的信息及其佔用量。
jstat -gcold pid:old對象的信息。
jstat -gcoldcapacity pid:old對象的信息及其佔用量。
jstat -gcpermcapacity pid: perm對象的信息及其佔用量。
jstat -printcompilation pid:當前VM執行的信息。
jstat -gcutil pid 1000 100 : 1000ms統計一次gc情況統計100次;
除了以上一個參數外,還可以同時加上 兩個數字,如:jstat -printcompilation 3024 250 6是每250毫秒打印一次,一共打印6次,還可以加上-h3每三行顯示一下標題。
(5)jconsole:
jconsole是一個用java寫的GUI程序,用來監控VM,並可監控遠程的VM,非常易用,而且功能非常強。使用方法:命令行裏打 jconsole,選則進程就可以了。
jstack ( 查看jvm線程運行狀態,是否有死鎖現象等等信息) : jstack pid : thread dump
MemoryAnalyzer 查看jmap dump 的內存對象工具 (https://blog.csdn.net/zhanshenzhi2008/article/details/89070049)
4、場景模擬
通過設置較小的jvm堆、線程棧、young、older,在程序運行過程中,可以觀察到程序不斷髮送gc,甚至導致程序功能無法正常執行。
5、jvm配置方法
(1) 設置Eclipse內存使用情況
修改eclipse根目錄下的eclipse.ini文件
-vmargs //虛擬機設置
-Xms40m //初始內存
-Xmx256m //最大內存
-Xmn16m //最小內存
-XX:PermSize=128M //非堆內存
-XX:MaxPermSize=256M
(2)JVM內存設置
打開eclipse window-preferences-Java -Installed JREs -Edit -Default VM Arguments
在VM自變量中輸入:-Xmx128m -Xms64m -Xmn32m -Xss16m
(3)Tomcat內存設置
打開Tomcat根目錄下的bin文件夾,編輯catalina.bat
修改爲:set JAVA_OPTS= -Xms256m -Xmx512m
6、配置參數
JVM的Heap分配可以使用-X參數設定,
-Xms
初始Heap大小
-Xmx
java heap最大值
-Xmn
young generation的heap大小
JVM有2個GC線程
第一個線程負責回收Heap的Young區
第二個線程在Heap不足時,遍歷Heap,將Young 區升級爲Older區
Older區的大小等於-Xmx減去-Xmn,不能將-Xms的值設的過大,因爲第二個線程被迫運行會降低JVM的性能。
爲什麼一些程序頻繁發生GC?
有如下原因:
1.程序內調用了System.gc()或Runtime.gc()。
2.一些中間件軟件調用自己的GC方法,此時需要設置參數禁止這些GC。
3.Java的Heap太小,一般默認的Heap值都很小。
4.頻繁實例化對象,Release對象 此時儘量保存並重用對象,例如使用StringBuffer()和String()。
如果你發現每次GC後,Heap的剩餘空間會是總空間的50%,這表示你的Heap處於健康狀態,許多Server端的Java程序每次GC後最好能有65%的剩餘空間
經驗之談:
1.Server端JVM最好將-Xms和-Xmx設爲相同值。爲了優化GC,最好讓-Xmn值約等於-Xmx的1/3。
2.一個GUI程序最好是每10到20秒間運行一次GC,每次在半秒之內完成。
注意:
1.增加Heap的大小雖然會降低GC的頻率,但也增加了每次GC的時間。並且GC運行時,所有的用戶線程將暫停,也就是GC期間,Java應用程序不做任何工作。
2.Heap大小並不決定進程的內存使用量。進程的內存使用量要大於-Xmx定義的值,因爲Java爲其他任務分配內存,例如每個線程的Stack等。
Stack的設定
每個線程都有他自己的Stack。
-Xss
每個線程的Stack大小
Stack的大小限制着線程的數量。如果Stack過大就好導致內存溢漏。-Xss參數決定Stack大小,例如-Xss1024K。如果Stack太小,也會導致Stack溢漏。
主要通過以下的幾個jvm參數來設置堆內存的:
-Xmx512m |
最大總堆內存,一般設置爲物理內存的1/4 |
-Xms512m |
初始總堆內存,一般將它設置的和最大堆內存一樣大,這樣就不需要根據當前堆使用情況而調整堆的大小了 |
-Xmn192m |
年輕帶堆內存,sun官方推薦爲整個堆的3/8 |
堆內存的組成 |
總堆內存 = 年輕帶堆內存 + 年老帶堆內存 + 持久帶堆內存 |
年輕帶堆內存 |
對象剛創建出來時放在這裏 |
年老帶堆內存 |
對象在被真正會回收之前會先放在這裏 |
持久帶堆內存 |
class文件,元數據等放在這裏 |
-XX:PermSize=128m |
持久帶堆的初始大小 |
-XX:MaxPermSize=128m |
持久帶堆的最大大小,eclipse默認爲256m。如果要編譯jdk這種,一定要把這個設的很大,因爲它的類太多了。 |
以上內容僅作實踐記錄參考,文字來自以下博客個人整理。
更多內容參考:
- https://blog.csdn.net/happysaz/article/details/81080627
- https://www.jianshu.com/p/cbde714e6de8
- https://blog.csdn.net/summer_huan/article/details/73649746
- https://blog.csdn.net/guangrong1/article/details/79500182
- https://blog.csdn.net/zhanshenzhi2008/article/details/89070049
- https://www.cnblogs.com/Darrenblog/p/10712125.html