问题描述
我发现 a bug in logback 当它试图删除其他东西(例如外部进程)持有引用的文件时会出现。通常,如果我关闭外部进程,问题就会消失,但我也遇到过这样的情况,而不是要删除的日志文件的单个文件句柄,突然我有 两个 文件句柄用于那个Java进程到同一个文件。对我来说,这似乎是两个不同的类持有同一个文件,或者有两个线程争用同一个资源。
无论如何,我想知道文件中的内容。我怎样才能知道呢?我需要处理的只是文件名和进程 ID。
一些随意浏览提到对进程进行堆转储并使用 Visual VM 和 OQL 查询语言检查它,但我不完全确定如何在 Windows 服务器上执行此操作,因为示例都针对 Linux 及其文件描述符系统。
解决方法
我通常使用 Eclipse MAT 和 OQL 从堆转储中获取此类信息。
路线#1:使用 java.io.FileDescriptor
是的,可以使用 FileDescriptor 信息在堆中找出您的文件对象。
- 运行此 OQL 命令:
SELECT fd.parent.path.toString() FROM java.io.FileDescriptor fd
- 获得对象列表后,您必须检查路径并找出您感兴趣的文件。
- 然后右键单击该对象 > 合并最短路径到 GC 根 > 排除所有幻像/弱/软等引用
- 您可能需要深入了解一下,以找出保存该文件的 GC 根
route#2:搜索所有字符串
假设日志文件名存储在某个地方,我们正在寻找该名称。此方法比前一个方法花费的时间稍长,因为 MAT 必须搜索所有 String 对象。
- 运行此 OQL 命令:
select * from java.lang.String s where s.toString().contains("myFileName")
- 获得该对象列表后,您必须检查路径并找出您感兴趣的文件。
- 重复上述第 3 步和第 4 步以获得 GC 根目录。
一旦你获得了 GC 根,如果它是一个线程,那么你也可以通过以下方式获得堆栈跟踪:
- 右键单击该线程对象
- Java 基础知识 > 线程详细信息