2

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

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

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

4

1 回答 1

3

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

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

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

  1. 运行此 OQL 命令:

从 java.io.FileDescriptor fd 中选择 fd.parent.path.toString()

  1. 获得该对象列表后,您必须检查路径并找出您感兴趣的文件。
  2. 然后右键单击该对象 > Merge Shortest Path To GC Roots > Exclude all phantom/weak/soft etc. references
  3. 您可能需要深入研究以找出持有该文件的 GC Root

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 基础 > 线程详细信息
于 2021-06-25T16:01:59.933 回答