java內存申請和釋放均是由jvm在控制。而釋放每每會出現各類各樣的問題,常常一個引用沒處理好就引發內存泄漏,最後引起OOM。若是發生在重要業務系統還可能出現嚴重的生產事故。 所以內存使用必定要謹慎,特別是引用要及時斷鏈。雖然jvm有GC(垃圾回收引擎),但只能清理沒有引用的對象,所以對象在不使用時及時置null。固然,筆者對此是很當心的,但萬萬沒想到仍是遇到了fullGC(old GC)。java
一般遇到的是堆區內存問題,也就是堆GC。jvm的GC發展到如今也經歷不少發展了,如今主要仍是分代回收的思路。算法
伊甸園,新生對象放置的地方。數據庫
在jvm中的被回收過對象仍存活的地方。數據結構
倖存區被清理後仍活着的對象就步入老年了。 大多數GC問題都在老年代中被發現,筆者遇到的問題也是在這裏。eclipse
eden 和survivor都屬於新生代,與old gen有明顯差異,也就是這樣決定了java程序不用主動回收也能在較好的狀態運行。 eden和survivor空間相對old generation小不少,這也意味着存放的內存也少不少。jvm通常將長期引用(jvm會將對象分析其引用計數)的對象(屢次GC仍存活的)放在Old generation中。jvm
jvm堆區不一樣區域使用的是不一樣算法,eden和survivor的GC屬於miniGC,也就是局部GC,特色是速度快,低延遲(1.標記複製算法與空間小的優點,2.GC時須要將全部線程掛起Stop The World)。而old generation發生GC則爲FullGC,且old generation用的是標記整理算法,線程扶起時間會很長。頻繁的fullGC多是程序設計不合理或內存參數不合理。工具
這兩天筆者遇到一個問題致使了fullGC發生。將進程進行dump分析 jmap
命令配合工具 MAT(eclipse提供)發現是部分局部變量佔用太多空間未及時釋放形成而且佔用了55%以上的內存空間。 爲何局部變量還會未及時釋放?查閱源代碼發現全部引用處均未發現被全局對象、靜態對象引用。ArrayList和LinkedList佔用內存太高,但也未被全局對象和靜態對象引用。spa
感受程序被幽靈附身了!!! 不存在的,直覺告訴我這種問題確定在本身的程序上。繼續分析果真發現了問題所在:發現對象內的值關聯性很是強,繼續分析最終找到數據庫查詢參數。會不會是數據形成?面對這個疑問diff了最近數據的狀況。線程
最近數據量暴增! 數量增長了6倍+,空間增長了3倍+。設計
因爲數據結構和業務邏輯的特殊性將同條件的數據所有查出來處理了,因爲數據全是相互存在引用,eden空間沒法分配進行了miniGC。miniGC後空間仍然不足,就這樣新生對象直接進入old generation。才生出來就進入老年 >_<。 而後因爲處理很快結束,生成的這些對象也再也不有引用。可是在old generation中不會當即GC,並且只有fullGC才能將其釋放。也就成了「短命的大對象」、「短命的老年對象」 ==!
知道了緣由就當即分析獲得瞭解決方案。儘可能不要構建局部的大對象!!!所以將DB中查詢出的量控制住,增長中間對象的數量,用完即置null。使得eden中及時GC,old generation增加穩定。 修改程序代碼再將壓一下,發現old generation增加緩下來了,問題解決。
若是遇到相似問題還能夠用jconsole和jvisual兩款工具實時監控jvm狀態、對象實例指標等。
很差的消息:jdk9已將jvisual去除,要使用jvisual請使用jdk8。jdk10中jconsole也沒了。。 jmap分析吧。。。