简体   繁体   English

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

[英]Find out which class/instance holds a reference to an open file

I found a bug in logback that arises when it tries to delete a file that something else (such as an external process) holds a reference to.在 logback中发现了一个错误,当它尝试删除其他内容(例如外部进程)引用的文件时,就会出现该错误 Usually, the issue goes away if a I close the external process, but I have also experienced that, instead of a single file handle to the logfile that was to be deleted, suddenly I have two file handles for that Java process to the same file.通常,如果我关闭外部进程,问题就会消失,但我也遇到过这样的情况,而不是要删除的日志文件的单个文件句柄,突然间我有该 Java 进程的两个文件句柄到同一个文件. To me, that seems like either two different classes are holding on to the same file, or there are two threads contending for the same resource.对我来说,这似乎是两个不同的类持有同一个文件,或者有两个线程争用同一个资源。

In any case, I would like to know what is holding on to the file.无论如何,我想知道文件中保存了什么。 How can I get to know that?我怎样才能知道呢? All I have to work with is the name of the file and the process id.我需要处理的只是文件名和进程 ID。

Some casual browsing mentions taking a heap dump of the process and inspecting it using Visual VM and the OQL query language, but I am not totally sure how to do that on a Windows server, as the examples have all targetted Linux and its system of file descriptors.一些随意浏览提到获取进程的堆转储并使用 Visual VM 和 OQL 查询语言检查它,但我不完全确定如何在 Windows 服务器上执行此操作,因为示例都针对 Linux 及其文件系统描述符。

I normally use Eclipse MAT and OQL to get that type of information out of heap dump.我通常使用Eclipse MAT和 OQL 从堆转储中获取此类信息。

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

Yes, it is possible to use FileDescriptor information to find out your file object in heap.是的,可以使用 FileDescriptor 信息在堆中找出文件对象。

  1. Run this OQL command:运行此 OQL 命令:

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

  1. Once you get that object list, you have to check paths and find out the file you are interested in.获得该对象列表后,您必须检查路径并找出您感兴趣的文件。
  2. Then right-click on that object > Merge Shortest Path To GC Roots > Exclude all phantom/weak/soft etc. references然后右键单击该对象> Merge Shortest Path To GC Roots > Exclude all phantom/weak/soft 等引用
  3. You may need to drill-down a bit to find out the GC Root which is holding onto that file您可能需要深入了解一下,以找出持有该文件的 GC Root

route#2: searching all Strings路线#2:搜索所有字符串

Assumption is that log file name is getting stored in somewhere and we are looking for that name.假设日志文件名存储在某个地方,我们正在寻找该名称。 This method takes little bit longer than the previous one as we are MAT has to search through all String objects.此方法比前一个方法花费的时间稍长,因为 MAT 必须搜索所有 String 对象。

  1. Run this OQL command:运行此 OQL 命令:

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

  1. Once you get that object list, you have to check paths and find out the file you are interested in.获得该对象列表后,您必须检查路径并找出您感兴趣的文件。
  2. Repeat step#3 and #4 as mentioned above to get the GC root.如上所述重复步骤#3 和#4 以获取GC 根。

Once you get the GC root and if it is a thread then you can get stack trace also by:一旦你获得了 GC 根,如果它是一个线程,那么你也可以通过以下方式获得堆栈跟踪:

  1. Right-click on that thread object右键单击该线程对象
  2. Java Basics > Thread Details Java 基础 > 线程详细信息

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM