我正在开发一个相当复杂的Web应用程序,它可以在一个控制器中调用几个外部执行的进程,一个grails后台进程和几个文件的读/写。一切都很好,直到我在近距离接近许多请求测试它。当我这样做时,我在我的tomcat catalina日志文件中收到以下java错误消息:
WARNING: Exception executing accept
java.net.SocketException: Too many open files
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:408)
at java.net.ServerSocket.implAccept(ServerSocket.java:462)
at java.net.ServerSocket.accept(ServerSocket.java:430)
at org.apache.jk.common.ChannelSocket.accept(ChannelSocket.java:312)
at org.apache.jk.common.ChannelSocket.acceptConnections(ChannelSocket.java:666)
at org.apache.jk.common.ChannelSocket$SocketAcceptor.runIt(ChannelSocket.java:877)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:690)
at java.lang.Thread.run(Thread.java:662)
起初,经过一些快乐的googeling和阅读之后,我怀疑它可能是一个“系统问题”,即我必须为执行tomcat的用户提高打开文件的限制 - 但事实并非如此。
然后我开始阅读很多关于Java的建议,而不是Grails& Groovy,因为如果你谷歌用Grails这个问题,你找不到这么多。我现在怀疑我的问题是由“太多的开放流”(或类似的东西)引起的,而不是实际打开的文件太多(因为打开文件的数量确实不大)。
我在一个闭包中有以下四种类型的大量操作:
1)打开文件并写信给他们:
def someFile = new File("/some/file.txt")
someFile << "Some content\n"
2)执行命令:
def cmd = "bash some-cmd".execute()
cmd.waitFor()
3)从文件中读取内容:
def fileContent = new File("/some/file.txt").text
4)从网络上的文件中读取内容:
def URL url = new URL("http://www.some.link");
def URLConnection uc = url.openConnection()
def BufferedReader br = new BufferedReader(new InputStreamReader(uc.getInputStream()))
...
br.close()
正如你所看到的,我唯一明确关闭的是具有InputStream的BufferedReader,我相信br.close()会将它们都关闭。
我是否必须关闭任何其他已打开的连接,或者更好:我可以这样做吗?这样做的命令是什么?或者你认为我的问题真的不是由“被遗忘的开放流”造成的?
我的问题主要来自Why do I get "Too many open files" errors?和IOException: Too many open files的答案。
我正在使用grails 1.1.1(我知道它已经过时但我在将应用程序迁移到当前版本时出现了严重问题,并且在经过数小时的工作后我放弃了它),groovy 1.8.0,tomcat 6.0。 28,ubuntu 10.10上的apache 2.2.16。
解决我的“太多打开文件”问题的答案与Stephen C的答案非常相关。似乎我的错误的第一个原因确实是未关闭的BufferedReader Stream。我基本上将他的java代码建议直接转移到了grails:
def URL url = new URL("http://www.some.link");
def URLConnection uc = url.openConnection()
def BufferedReader br = new BufferedReader(new InputStreamReader(uc.getInputStream()))
try{
...
}finally{
br.close()
}
- &GT;这肯定解决了“打开太多文件”的问题,现在我甚至能够看到问题的真正根源。
答案 0 :(得分:4)
正如你所看到的,我唯一明确关闭的是具有InputStream的BufferedReader,我相信br.close()会将它们都关闭。
它确实......但只有在执行时才会这样。
我不是一个groovy / grails程序员,但在Java中,人们常常会犯这样的错误,导致文件描述符泄漏。例如,
InputStream is = new FileInputStream(someFile);
// do some work
...
is.close();
问题是省略号(...)指示的语句可能会抛出异常。如果他们这样做,is.close()
调用不会发生,并且文件描述符被泄露。解决方案(在Java中)是编写如下代码:
InputStream is = new FileInputStream(someFile);
try {
// do some work
...
} finally {
is.close();
}
或(在Java 7中):
try (InputStream is = new FileInputStream(someFile)) {
// do some work
...
}
答案 1 :(得分:0)
似乎在您的应用程序中创建了太多文件或套接字。你需要增加文件限制。
如果您使用的是linux,请使用ulimit
设置系统的最大文件限制。
在linux中,默认文件限制为1024
ulimit -n 2048 // to set the file limit to 2048
答案 2 :(得分:0)
@Sunil Kumar Sahoo和@Stephen C的答案都适用。
通常,您按此顺序执行以下步骤: