一次JVM內存溢出問題解決記錄

問題解決有一段時間了,當時比較忙,沒有記錄下來,最近閒下來了,就打算記錄一下,問題的解決過程,畢竟以前看過虛擬機相關的知識,但由於公司項目都是內部項目,對性能要求不太高,很少用到虛擬機知識進行優化之類的,用虛擬機知識解決問題的機會也不多。

先說下背景,這是一個電商相關的項目,已經上線運行了有段時間了,沒用maven管理依賴,用到的jar包直接放在了工程裏,Spring+struts+hibernate實現的,本身提供了電商頁面管理的功能,通過頁面,可以管理商品,管理活動,然後通過freemarker生成靜態頁面,上傳服務器,原來是ftp上傳服務器,和這個項目在同一個服務器上,生成的靜態頁面是分爲不同電商終端訪問的,比如有微信端,有app端等等,由於靜態文件生成後上傳ftp與該項目在同一服務器上,後來性能感覺不太夠用了,就想把靜態文件分離出來,上傳到OSS上,這個任務當時由我來做的,由於用到OSS,所以jdk由原來的jdk7升級爲jdk8,tomcat也由tomcat7升爲tomcat8。

問題的發生是這樣的,部署到生產環境後,每十個小時左右服務會掛一次,看日誌是堆內存溢出了,不過回憶了下當時理出來的業務,還有我們當時做過的改動,想不出哪裏會導致溢出的,所以就到線上把JVM內存dump出來轉儲到文件裏,然後把文件下下來到本地,用工具打開分析,用的是eclipse memory analyzer來分析(第一次用,之前就用的jdk自帶的工具看過那麼兩次dump出來的堆文件),這個工具感覺還是挺好用的,直接就看到了佔內存最大的是哪個對象,是一個Blocking隊列,裏面存的對象是LoggingEvent對象,看着像是和日誌相關的類,查了下,還確實是日誌相關包裏的類,工程代碼裏應該沒有用到纔對,只好在本地啓動工程,然後在隊列的添加對象方法中加斷點,然後就發現很快進到了斷點,看了下隊列的size,運行沒多少時間就已經有幾十萬對象了,確實很大,看了下斷點處的調用棧,感覺和業務代碼沒有太大關係,都是Spring框架代碼,然後一直在日誌相關包中來回調用,最後就調到了加入隊列的代碼。

然後和另外兩個同事討論了一翻,最後猜測,可能是日誌門面slf4j獲取到的日誌信息沒有最終打到文件,而是直接保存到了內存裏,導致隊列一直增加,最終內存溢出,而原來這些日誌依賴並沒有問題,應該是和jdk還有tomcat的升級有關的,所以我先把項目裏所有日誌相關的包刪除了,再找了個運行環境也是dk8,tomcat8的項目打的war包,把裏面的所有日誌包拷出來放到項目裏,在本地啓動,發現問題已經順利解決。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章