How to find leaked file descriptors in Java application using Byteman
Environment
- Java
Issue
A Java application is not calling FileInputStream.close() correctly, and leaves the files open until the garbage collector finalizes them. Is there any way to find what files are being leaked?
Resolution
Attach Byteman to your application using steps in Using Byteman to troubleshoot Java issues and add the following rules:
RULE attach creator trace to FileInputStream
CLASS FileInputStream
METHOD <init>(File)
AT EXIT
IF TRUE
DO traceOpen($0.getClass(), "FileInputStream.txt");
traceStack("opening " + $1.getPath() + " as " + $0.fd + " ", $0.getClass())
ENDRULE
RULE flag as closed
CLASS FileInputStream
METHOD close
AT ENTRY
IF TRUE
DO flag($0)
ENDRULE
RULE print finalising
CLASS FileInputStream
METHOD finalize
AT ENTRY
IF !flagged($0)
DO traceln($0.getClass(), "finalizing " + $0.fd)
ENDRULE
Every "finalizing" entry in the log indicates a file that was not closed properly (and the garbage collector finalized it). Looking at the "opening" entry with the same id will show the stack trace of where it was opened.
You can get a list of all leaked file descriptors by using
IDS=$(grep finalizing FileInputStream.txt | sed -e 's/.*@//' | tr '\n' '|') egrep "opening.*(${IDS%?})" FileInputStream.txt | sed -e 's/opening//' -e 's/ as .*//' | sort | uniq -c | sort -n
Seeing all the leaked files with 20 stack frames by running:
IDS=$(grep finalizing FileInputStream.txt | sed -e 's/.*@//' | tr '\n' '|') egrep -A20 "opening.*(${IDS%?})" FileInputStream.txt
This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.