java 单元测试有什么好的模式可以确保正确关闭文件?
我的代码库中有一个问题,我们没有正确关闭文件句柄,或者可能是流。我们最终在非常重的负载下得到了 TooManyOpenFiles 异常。根据 lsof 的输出,我们非常确定我们知道泄漏在哪里(在我们的日志系统中),但我的问题是:如何编写一个单元测试来检查完成后资源是否已正确关闭?有没有办法查询 JRE 以了解当前打开了多少个文件?我可以以某种方式拦截文件操作以便监视它们吗?
我怀疑我必须检测我的代码才能管理所有文件 I/O、计数引用并确保它们以这种方式关闭,但如果有人知道类似于我上面提到的那些想法的自上而下的解决方案,这将是一个巨大的帮助!
I have an issue in my codebase where we are not properly closing file 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!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
既然您正在谈论测试,PowerMock http://code.google.com/p/powermock/ 可能会成功。如果我没有记错的话,它可以模拟静态方法和构造函数。因此,您可以模拟/监视构造函数和关闭方法或释放资源所需的任何内容。
我试图在我的测试中避免它,但在你描述的情况下,这可能是值得的麻烦。
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.
您可以使用面向方面的编程(AOP)工具,例如 AspectJ 来添加代码来计算打开/关闭的文件数到
FileInputStream
和FileOutputStream
。这相当容易做到(当然,细节取决于工具),稳健且非侵入性。You can use aspect-oriented programming (AOP) tool like AspectJ to add code to count open/closed files to
FileInputStream
andFileOutputStream
. This is fairly easy to do (details depend on the tool, of course) robust and noninvasive.看来您可以通过 JMX 观看此内容。
有人在这里发布了代码:
http://java-monitor.com/forum/showthread.php?t=130
如果您尚未启用 JMX,则必须在 JVM 中启用 JMX。
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.
您可以为普通 IO 类、FileInputStream 等编写自己的“库”。它跟踪(在测试中)调用者打开它的内容(如果它仍然打开)、全局列表等。让它包装一个“真正的”FileInputStream。
然后在代码中的任何地方使用它而不是“普通”FileInputStream 等。
然后在单元测试结束时断言 WrappedFileInputStreams.assertAllWereClosed 或其他什么。
另一种选择是编写您的方法,以便它们以某种方式接受 FileinputStream 作为参数,然后调用它们,然后断言您的参数在方法结束后“立即关闭”。
或者,如果您知道您将使用 Linux,请对
lsof
进行系统调用,它不应将任何文件列为位置“(已删除)”。 https://unix.stackexchange.com/a/64737/8337由于某些原因,在 OS X 上并非如此很简单,它不会显示“(已删除)”,但您仍然可以通过循环 lsof -p ... 并检查每个文件是否确实存在于文件系统上来检测文件是否已消失...
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/8337For 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...