堆內存溢出:
此種溢出,加內存只能緩解問題,不能根除問題,需優化代碼
堆內存中存在大量對象,這些對象都有被引用,當所有對象占用空間達到堆內存的最大值,就會出現內存溢出OutOfMemory:Java heap space
永久代溢出
如果發生,則是在初始化的時候,空間太小,解決辦法,擴大空間
類的一些信息,如類名、訪問修飾符、字段描述、方法描述等,所占空間大於永久代最大值,就會出現OutOfMemoryError:PermGen space
內存溢出的檢測方法:pid=1730
Jdk/bin目錄下有很多檢測工具
圖形界面:
Jconsole
Jvisualvm
命令行工具:
Jstat –gcutil pid 1000 100 (只需要看O,如果達到100%,並且長期處於100%,則代表老年代內存不足)
pid:進程號、1000:1秒鍾獲取一次、100一共獲取100次
E:eden區
O:老年代
P:永久代
YGC:新生代的GC次數
YGCT:當前統計的YGC一共花費的時間(毫秒)
FGC:fullGC老年代的GC次數
FGCT:當前統計的FGC一共花費的時間(毫秒)
GCT:YGC+FGC
Jmap –histo pid | head -20
把當前JVM里面的所有對象打印出來,排序,head:頭部,head -20 前20行
Jmap –heap pid(列出當前進程的堆的數據,一般用來看當前配置)
在jvisualvm上面也可以看到JVM參數
FullGC頻率:單次FullGC時間<200ms
Jvm常見參數
-Xms2048m,初始堆大小,建議<物理內存的1/4,默認值為物理內存的1/64
-Xmx2048m,最大堆大小,建議與-Xms保持一致,默認值為物理內存的1/4
-Xmn512m,新生代大小,建議不超過堆內存的1/2
-Xss256k,線程年輕代堆棧大小,建議256k
-XX:PermSize=256m,永久代初始值,默認值為物理內存的1/64
-XX:MaxPermSize=256m,永久代最大值,默認值為物理內存的1/4
-XX:SurvivorRatio=8:年輕帶中Eden區和Survivor區的比例,默認為8:1:1,即Eden(8),From Space(1),ToSpace(1)
-XX:+UseConcMarkSweepGC:開啟CMS垃圾回收器
看一下內存溢出的情況
先配置一下tomcat里面JVM的參數:vi /home/server/tomcat-PerfTeach01/bin/catalina.sh
由於ip變了,改一下host里面的ip
啟動tomcat
能訪問,代表啟動成功:http://localhost:8080/PerfTeach/MemoryLeak?userId=123&password=abc&waitTime=3
jmeter5個並發永遠跑
TPS
響應時間
cpu
jstat -gcutil 1730 1000 1000
jvisualvm
看一下tomcat日志的后200行
有內存溢出的報錯
看當前JVM里面的所有對象,找com開頭的,業務代碼,再找非java開頭的
可以看出org.apache可能有問題,com.lee是業務代碼,一定有問題
直接告訴開發,讓開發去解決
jvisualvm也可以生成快照,一開始出現內存泄漏的時候就點堆Dump在服務器下生成快照,下載后再用 jvisualvm打開, jvisualvm_文件_裝入_文件類型選“線程 Dump”
由於這個內存泄漏的原因其實是session引起的,所以最好把tomcat的session持久化取消掉,以免下次啟動tomcat又加載上一次保留的session
修改:tomcat目錄下conf/context.xml,將 <Manager pathname="" />這行的注釋打開
把注釋打開
內存泄漏的本質:老年代空間里面東西放滿了,又不能被回收
程序一旦出現內存泄漏,就算停止壓測也不能解決,只能重啟
內存泄露會出現的現象
1,tps出現大幅波動,並慢慢降低,甚至降為0,響應時間隨之波動,慢慢升高
2,通過jstat命令看到,Jvm中Old區不斷增加,FullGC非常頻繁,對應的FullGC消耗的時間也不斷增加
3,通過jconsole/jvisualvm可以看到,堆內存曲線不斷上升,接近上限時,變成一條直線
4,日志報錯java.lang.OutOfMemoryError: Java heap space
內存泄露定位
1,通過jmap命令:jmap -histo pid | head -20,查看當前堆內存中實例數和占用內存最多的前20個對象
2,通過jvisualvm,進行遠程堆dump,然后把dump文件下載下來,用jvisualvm打開進行分析,可以看到更直觀的jvm中對象的信息
監控內存泄露問題的場景
1,在試壓階段,或任意場景都可以考慮通過jvisualvm和jstat監控jvm的情況
2,在穩定性場景中,一定要關注Jvm內存使用的情況,在長時間的壓測下,最容易看出內存泄露的問題
JVM參數調優
Jvm常用參數
---------------------------------------
堆內存 = 年輕代+老年代
年輕代 = Eden+Survivor
Survivor = From Space+To Space
---------------------------------------
年輕代 = Eden+From Space+To Space
堆內存=Eden+From Space+To Space+老年代
====================================
-Xms2048m,初始堆大小,建議<物理內存的1/4,默認值為物理內存的1/64
-Xmx2048m,最大堆大小,建議與-Xms保持一致,默認值為物理內存的1/4
-Xmn512m,新生代大小,建議不超過堆內存的1/2
-Xss256k,線程堆棧大小,建議256k
-XX:PermSize=256m,永久代初始值,默認值為物理內存的1/64
-XX:MaxPermSize=256m,永久代最大值,默認值為物理內存的1/4
-XX:SurvivorRatio=8:年輕帶中Eden區和Survivor區的比例,默認為8:1,即Eden(8),From Space(1),ToSpace(1)
-XX:MaxTenuringThreshold=15:晉升到老年代的對象年齡,每個對象堅持過一次MinorGC后對象年齡+1,默認值是15,年齡超過15進入到老年代,該參數在串行GC時有效
-XX:PretenureSizeThreshold=3145728:單位字節,只對Serial和ParNew兩款收集器有效,新生代采用Parallel Scavenge GC時無效,大於這個值的對象直接在老年代進行分配
非穩定參數,使用方式主要有以下三種:
1,-XX +<option>:開啟option參數
2,-XX -<option>:關閉option參數
3,-XX <option>=<value>:將option參數的值設置為value
client模式,Jvm默認垃圾收集器
UseSerialGC:新生代采用Serial收集器,老年代采用Serial Old收集器
server模式,Jvm默認垃圾回收期
UseParallelGc:新生代采用Parallel Scavenge收集器,吞吐量優先的收集器,老年代采用Serial Old收集器
-XX:+UseConcMarkSweepGC:默認關閉,ParNew+CMS+Serial Old,當CMS收集器出現ConcurrentModeFailure錯誤(Jvm預留空間不足以容納程序使用),采用后備收集器Serial Old
CMS相關參數
-XX:CMSInitiatingOccupancyFraction=80:CMS收集器在老年代空間被使用多少時觸發FullGC,默認為92,建議80左右
-XX:+UseCMSCompactAtFullCollection:CMS收集器在FullGC時開啟內存碎片的壓縮,默認關閉
-XX:CMSFullGCsBeforeCompaction=8:執行多少次不壓縮FullGC后,進行一次壓縮,默認是0(代表每次FullGC都進行壓縮)
-XX:+UseCMSInitiatingOccupancyOnly:使用手動定義初始化定義開始,禁止hostspot自行觸發CMS GC
-XX:ParallelGCThreads=8:並行收集器的線程數,此值最好配置與處理器數目相等 同樣適用於CMS
日志參數:
-XX:+HeapDumpOnOutOfMemoryError:當發生內存溢出時,進行堆內存dump,一般把這個打開
-XX:+PrintGCDetails:打印GC的詳細信息
======================================================================
企業實際配置
-server -Xms1028m -Xmx1028m -XX:PermSize=256m -XX:MaxPermSize=256m -Xmn512m -XX:MaxDirectMemorySize=1g -XX:SurvivorRatio=10
-XX:+UseConcMarkSweepGC
-XX:+UseCMSCompactAtFullCollection
-XX:CMSMaxAbortablePrecleanTime=5000
-XX:+CMSClassUnloadingEnabled
-XX:CMSInitiatingOccupancyFraction=80
-XX:+UseCMSInitiatingOccupancyOnly
-XX:ParallelGCThreads=8
-Xloggc:/home/admin/logs/gc.log
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/home/admin/logs/java.hprof
建議閱讀《深入理解Java虛擬機》