I have an issue in my codebase where we are not properly closing f开发者_C百科ile handles, or probably streams. We eventually get a TooManyOpenFiles exception under very heavy load. Based on the output of lsof, we are pretty sure we know where the leak is (in our logging system), but my question is: how can I write a unit test that checks, when it's complete, that resources have been closed properly? Is there a way to query the JRE to find out how many files are currently open? Can I somehow intercept file operations so I can monitor them?
I suspect I will have to instrument my code in order to manage all the file I/O, count references, and make sure they are getting closed that way, but if anyone knows of a top-down solution akin to those ideas I mentioned above, that would be a huge help!
Since you are talking about Tests, PowerMock http://code.google.com/p/powermock/ might do the trick. It makes it possible to mock static methods and constructors if I am not mistaken. So you could mock/spy on the constructors and on the close methods or what ever you need for freeing the resources.
I try to avoid it in my tests but in the case which you describe it might be worth the hassle.
You can use aspect-oriented programming (AOP) tool like AspectJ to add code to count open/closed files to FileInputStream
and FileOutputStream
. This is fairly easy to do (details depend on the tool, of course) robust and noninvasive.
Looks like you can watch this via JMX.
Someone posted code here: http://java-monitor.com/forum/showthread.php?t=130
You'll have to enable JMX in your JVM if you haven't already.
You could write your own "library" for the normal IO classes, FileInputStream, etc. That tracks (in test) what caller opened it, if it's still open, a global list, etc. Have it wrap a "real" FileInputStream. Then use that everywhere in your code instead of a "normal" FileInputStream et al.
Then at the end of your unit test you assert WrappedFileInputStreams.assertAllWereClosed
or what have you.
Another option would be to write your methods so they accept FileinputStream as a parameter somehow, then call them, then assert your parameter comes out "closed now" after the method ends.
Or if you know you'll be on linux, do a system call to lsof
and it should not list any files as location '(deleted)'. https://unix.stackexchange.com/a/64737/8337
For some reason on OS X it's not that easy, it doesn't show "(deleted)" but you could still detect if the file is gone by looping over lsof -p ...
and checking if each file is actually there on the file system...
精彩评论