歡迎光臨
每天分享高質量文章

從 JVM heap dump 裡查詢沒有關閉檔案的取用

(點選上方公眾號,可快速關註)


來源:Hengyunabc ,

hengyunabc.github.io/jvm-heap-dump-find-fd/

背景

最近排查一個檔案沒有關閉的問題,記錄一下。

哪些檔案沒有關閉是比較容易找到的,檢視行程的fd(File Descriptor)就可以。但是確定fd是在哪裡被開啟,在哪裡被取用的就複雜點,特別是在沒有重啟應用的情況下。

在JVM裡可以透過heap dump比較方便地反查物件的取用,從而找到洩露的程式碼。

以下麵簡單的demo為例,Demo會建立一個臨時檔案,並且沒有close掉:

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

public class Test {

public static void main(String[] args) throws IOException {

File tempFile = File.createTempFile(“test”, “ttt”);

FileInputStream fi = new FileInputStream(tempFile);

System.in.read();

}

}

透過檔案名查詢對應的fd

行程開啟的檔案在OS裡有對應的fd(File Descriptor),可以用lsof命令或者直接在linux下到/proc目錄下檢視。

以demo為例,可以找到test檔案的fd是12:

$ ls -alh /proc/11278/fd/

total 0

dr-x—— 2 admin users  0 Jun 30 18:20 .

dr-xr-xr-x 8 admin users  0 Jun 30 18:20 ..

lrwx—— 1 admin users 64 Jun 30 18:20 0 -> /dev/pts/0

lrwx—— 1 admin users 64 Jun 30 18:20 1 -> /dev/pts/0

lr-x—— 1 admin users 64 Jun 30 18:24 11 -> /dev/urandom

lr-x—— 1 admin users 64 Jun 30 18:24 12 -> /tmp/test7607712940880692142ttt

對行程進行heap dump

使用jmap命令:

jmap -dump:live,format=b,file=heap.bin 11278

透過OQL查詢java.io.FileDescriptor物件

對於每一個開啟的檔案在JVM裡都有一個java.io.FileDescriptor物件。檢視下原始碼,可以發現FileDescriptor裡有一個fd欄位:

public final class FileDescriptor {

    private int fd;

所以需要查詢到fd等於12的FileDescriptor,QOL陳述句:

select s from java.io.FileDescriptor s where s.fd == 12

使用VisualVM裡的OQL控制檯查詢

在jdk8裡自帶VisualVM,jdk9之後可以單獨下載:https://visualvm.github.io/

把heap dump檔案匯入VisualVM裡,然後在“OQL控制檯”查詢上面的陳述句,結果是:

再可以查詢到parent,取用相關的物件。

使用jhat查詢

除了VisualVM還有其它很多heap dump工具,在jdk裡還自帶一個jhat工具,儘管在jdk9之後移除掉了,但是個人還是比較喜歡這個工具,因為它是一個web介面的。

jhat -port 7000 heap.bin

訪問 http://localhost:7000/oql/ ,可以在瀏覽器裡查詢OQL:

開啟連結可以檢視具體的資訊

總結

  • 先找出沒有關閉檔案的fd

  • 從heap dump裡據fd找出對應的java.io.FileDescriptor物件,再找到相關取用

連結


  • ViauslVM

    https://visualvm.github.io/

  • Object Query Language (OQL)

    http://cr.openjdk.java.net/~sundar/8022483/webrev.01/raw_files/new/src/share/classes/com/sun/tools/hat/resources/oqlhelp.html

【關於投稿】


如果大家有原創好文投稿,請直接給公號傳送留言。


① 留言格式:
【投稿】+《 文章標題》+ 文章連結

② 示例:
【投稿】《不要自稱是程式員,我十多年的 IT 職場總結》:http://blog.jobbole.com/94148/

③ 最後請附上您的個人簡介哈~



看完本文有收穫?請轉發分享給更多人

關註「ImportNew」,提升Java技能

贊(0)

分享創造快樂