前言
最近生產環境有個老項目一直內存報警,不時的還出現內存泄漏,導致需要重啓服務器,已經嚴重影響正常服務了。
分析
1.dump內存文件
liunx使用如下命令:
1 |
|
2.使用Eclipse Memory Analysis進行分析
異常如下:
1 2 3 4 5 6 7 |
|
POI在加載Excel引發了內存泄漏,中間創建了大量的對象,佔用了大量的內存
3.查看上傳的Excel大小
經查看發現很多Excel大小在9M的文件
4.查看代碼POI讀取Excel的方式
發現使用的是用戶模式,這樣會佔用大量的內存;POI提供了2中讀取Excel的模式,分別是:
- 用戶模式:也就是poi下的usermodel有關包,它對用戶友好,有統一的接口在ss包下,但是它是把整個文件讀取到內存中的,
對於大量數據很容易內存溢出,所以只能用來處理相對較小量的數據; - 事件模式:在poi下的eventusermodel包下,相對來說實現比較複雜,但是它處理速度快,佔用內存少,可以用來處理海量的Excel數據。
經上面分析基本可以確定問題出在使用POI的用戶模式去讀取Excel大文件,導致內存泄漏。
本地重現
下面模擬一個600kb大小的Excel(test.xlsx),分別用兩種模式讀取,然後觀察內存波動;
1.需要引入的庫maven:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
2.用戶模式代碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
|
3.事件模式代碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
|
具體代碼來源:http://poi.apache.org/spreadsheet/how-to.html#xssf_sax_api
4.設置VM arguments:-Xms100m -Xmx100m
UserModel運行結果直接報OutOfMemoryError,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
UserModel模式下讀取600kbExcel文件直接內存溢出,看了600kbExcel文件映射到內存中還是佔用了不少內存;EventModel模式下可以流暢的運行。
5.設置VM arguments:-Xms200m -Xmx200m
UserModel模式和EventModel模式都可以正常運行,但是很明顯UserModel模式回收內存更加頻繁,而且在cpu的佔用上更高。
總結
通過簡單的分析以及本地運行兩種模式進行比較,可以看到UserModel模式下使用的簡單的代碼實現了讀取,但是在讀取大文件時CPU和內存都不理想;
而EventModel模式雖然代碼寫起來比較繁瑣,但是在讀取大文件時CPU和內存更加佔優。