How to find leaked file descriptors in Java application using Byteman

Solution Unverified - Updated

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
Category

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.