系統配置爲單核4G, web 工程配置堆2G, /tmp目錄 二進制文件不斷增長,平均一天增長20G, 手動清理/tmp目錄,重啓系統,問題依舊。java
2.lsof -p pid 肯定tmp文件都被進程id爲10791的同一個Java進程打開。mysql
根據上面的分析,這些文件應該是該進程的臨時文件,並且不斷在增長,有多是文件句柄泄露。linux
查看該進程的句柄圖 nginx
12.15號,系統打開的句柄數量在逐步的增長,並且沒有出現相對平穩的跡象,肯定是句柄泄露了,這印證了咱們的猜測。web
下來須要進一步分析到底是什麼緣由形成的句柄泄露。sql
谷歌搜索關鍵字,肯定FlateDecode是解碼 PDF stream 的一個工具。查看程序中引用相關pdf的代碼,以下圖所示:apache
public
static
byte
[] transfer(
byte
[] bytes,
int
pageNum)
throws
IOException {
LOG.info(
"PDF合同轉IMAGE開始...pageNum={}"
, pageNum);
PdfDecoder decode_pdf =
new
PdfDecoder(
true
);
decode_pdf.scaling =
1
.5F;
FontMappings.setFontReplacements();
byte
[] outbytes =
new
byte
[
0
];
ByteArrayOutputStream out =
new
ByteArrayOutputStream();
try
{
decode_pdf.openPdfArray(bytes);
//bytes is byte[] array with PDF
BufferedImage img = decode_pdf.getPageAsImage(pageNum);
ImageIO.write(img,
"jpg"
, out);
outbytes = out.toByteArray();
LOG.info(
"PDF合同轉IMAGE成功...pageNum={}"
, pageNum);
}
catch
(Exception e) {
LOG.error(
"PDF合同轉IMAGE異常...pageNum={},e={}"
, pageNum, e);
}
finally
{
out.close();
}
return
outbytes;
}
|
這段代碼用來將pdf轉化成一個jpg的圖片,使用了jpedal第三方庫。 windows
jpedal是一個開源的純Java的PDF文檔解析庫,能夠用來方便的查看和編輯文字和圖片。 api
回到代碼, 按照以往編碼的經驗,有多是PdfDecoder沒有釋放資源,致使生成的臨時文件一直沒有釋放掉。查看jpedal文檔,發現的確提供了closePdfFile 關閉pdf文件的方法。 緩存
finally 塊裏添加
decode_pdf.flushObjectValues(true);
decode_pdf.closePdfFile();
從新發版,發現以後句柄圖達到了相對平穩的狀態,tmp目錄也再也不繼續增長臨時文件。
雖然問題解決了,可是還有一些困惑。臨時文件怎麼生成的?page fault爲啥這麼多?
一、臨時文件究竟是怎麼生成的?
decode_pdf.openPdfArray(bytes) 根據傳進來的字節流 打開pdf文件,
jpedal在這裏作了一個優化,當pdf文件小於16k時或者alwaysCacheInMemory = -1時,直接內存緩存該pdf。
當pdf文件的大小大於16k時,會在臨時目錄下生成一個前綴爲page,後綴爲bin的二進制文件,該臨時目錄由系統參數 java.io.tmpdir 指定,默認在/tmp目錄下。
這樣,因爲線上環境的pdf基本都大於16k,因此/tmp目錄下就會看到不斷的臨時文件生成。這個臨時文件命名規則爲page***.bin。
二、添加closePdf文件以後,爲啥問題就解決了呢?
closePdf會調用PdfReader的closePdfFile()方法,該方法根據緩存的臨時文件名稱刪除該臨時文件。
三、未關閉pdf文件,爲啥會引發較多的page fault呢?
page fault 分爲 minor page fault 和major page fault。
major page fault也稱爲hard page fault, 指須要訪問的內存不在虛擬地址空間,也不在物理內存中,須要從慢速設備載入。從swap回到物理內存也是hard page fault。
minor page fault也稱爲soft page fault, 指須要訪問的內存不在虛擬地址空間,可是在物理內存中,只須要MMU創建物理內存和虛擬地址空間的映射關係便可。
(一般是多個進程訪問同一個共享內存中的數據,可能某些進程尚未創建起映射關係,因此訪問時會出現soft page fault)
正常狀況下,系統也會有一些pagefault,以下圖所示:
,因此pagefault和該問題沒有直接關係。minflt表示從內存加載數據時每秒出現的小的錯誤數目,能夠忽略。若是majflt較大,表示從磁盤載入內存頁面,發生了swap,此時須要關注。
咱們詳細的回顧了這次線上發生的問題,以及如何去定位,而後去解決問題的整個過程。
(1)問題發現,收到系統磁盤空間不足的報警。
(2)問題定位,先根據du確認是tmp目錄增加過快的問題,而後根據lsof和進程句柄圖肯定是文件句柄泄露,再根據臨時文件的文件內容,定位相關的源代碼,查看源代碼,確認是文件句柄資源沒有正確釋放。
(3)解決問題,查看api,確認是資源泄露的問題,修復代碼上線。