找出哪个类/实例持有对打开文件的引用

问题描述

我发现 a bug in logback 当它试图删除其他东西(例如外部进程)持有引用的文件时会出现。通常,如果我关闭外部进程,问题就会消失,但我也遇到过这样的情况,而不是要删除的日志文件的单个文件句柄,突然我有 两个 文件句柄用于那个Java进程到同一个文件。对我来说,这似乎是两个不同的类持有同一个文件,或者有两个线程争用同一个资源。

无论如何,我想知道文件中的内容。我怎样才能知道呢?我需要处理的只是文件名和进程 ID。

一些随意浏览提到对进程进行堆转储并使用 Visual VM 和 OQL 查询语言检查它,但我不完全确定如何在 Windows 服务器上执行此操作,因为示例都针对 Linux 及其文件描述符系统。

解决方法

我通常使用 Eclipse MAT 和 OQL 从堆转储中获取此类信息。

路线#1:使用 java.io.FileDescriptor

是的,可以使用 FileDescriptor 信息在堆中找出您的文件对象。

  1. 运行此 OQL 命令:

SELECT fd.parent.path.toString() FROM java.io.FileDescriptor fd

  1. 获得对象列表后,您必须检查路径并找出您感兴趣的文件。
  2. 然后右键单击该对象 > 合并最短路径到 GC 根 > 排除所有幻像/弱/软等引用
  3. 您可能需要深入了解一下,以找出保存该文件的 GC 根

route#2:搜索所有字符串

假设日志文件名存储在某个地方,我们正在寻找该名称。此方法比前一个方法花费的时间稍长,因为 MAT 必须搜索所有 String 对象。

  1. 运行此 OQL 命令:

select * from java.lang.String s where s.toString().contains("myFileName")

  1. 获得该对象列表后,您必须检查路径并找出您感兴趣的文件。
  2. 重复上述第 3 步和第 4 步以获得 GC 根目录。

一旦你获得了 GC 根,如果它是一个线程,那么你也可以通过以下方式获得堆栈跟踪:

  1. 右键单击该线程对象
  2. Java 基础知识 > 线程详细信息

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...