我正在处理一个庞大的遗留Java应用程序,其中有很多手写的东西,而现在你可以让框架来处理。
我现在面临的问题是我们在Solaris服务器上运行时会出现文件句柄不足的情况。我想知道跟踪打开文件句柄的最佳方法是什么?需要查看哪些内容以及可能导致文件句柄不足的原因是什么?
我不能在Solaris下调试应用程序,只能在我的Windows开发环境中。在Windows下分析打开的文件句柄甚至可行吗?
我正在处理一个庞大的遗留Java应用程序,其中有很多手写的东西,而现在你可以让框架来处理。
我现在面临的问题是我们在Solaris服务器上运行时会出现文件句柄不足的情况。我想知道跟踪打开文件句柄的最佳方法是什么?需要查看哪些内容以及可能导致文件句柄不足的原因是什么?
我不能在Solaris下调试应用程序,只能在我的Windows开发环境中。在Windows下分析打开的文件句柄甚至可行吗?
在Windows系统中,您可以使用“进程资源管理器”查看打开的文件句柄:
http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx
在Solaris系统中,您可以使用“lsof”命令监视打开的文件句柄。
我发现用FindBugs可以很好地追踪未关闭的文件句柄:
http://findbugs.sourceforge.net/
它检查了许多问题,但其中最有用的之一是资源打开/关闭操作。它是一个静态分析程序,运行在您的源代码上,并且也可作为eclipse插件使用。
#!/bin/bash
COUNTER=0
HOW_MANY=0
MAX=0
# do not take care about COUNTER - just flag, shown should we continie or not
while [ $COUNTER -lt 10 ]; do
#run until process with passed pid alive
if [ -r "/proc/$1" ]; then
# count, how many files we have
HOW_MANY=`/usr/sbin/lsof -p $1 | wc -l`
#output for live monitoring
echo `date +%H:%M:%S` $HOW_MANY
# uncomment, if you want to save statistics
#/usr/sbin/lsof -p $1 > ~/autocount/config_lsof_`echo $HOW_MANY`_`date +%H_%M_%S`.txt
# look for max value
if [ $MAX -lt $HOW_MANY ]; then
let MAX=$HOW_MANY
echo new max is $MAX
fi
# test every second. if you don`t need so frequenlty test - increase this value
sleep 1
else
echo max count is $MAX
echo Process was finished
let COUNTER=11
fi
done
jmap
和 jhat
,或者如果你想要一个 GUI,可以使用 jvisualvm
)。你可能有兴趣查找拥有 FileDescriptor
的对象。需要记住的是,在Unix系统中,打开的套接字也会消耗文件句柄。因此,可能是像数据库连接池泄漏(例如未关闭和返回到池中的打开数据库连接)这样的问题导致了这个问题 - 我确实曾经看到过由于连接池泄漏而引起的这个错误。
虽然这不是直接回答你的问题,但这些问题可能是由于在您的旧代码中错误地释放文件资源导致的。例如,如果您正在使用FileOutputsStream类,请确保在finally块中调用close方法,如下例所示:
FileOutputsStream out = null;
try {
//Your file handling code
} catch (IOException e) {
//Handle
} finally {
if (out != null) {
try { out.close(): } catch (IOException e) { }
}
}
/proc/PID/fd
目录。我记得Solaris有一个命令(也许是pfiles?)可以做同样的事情 - 您的系统管理员应该知道它。我建议您仔细检查Solaris服务器的环境设置。我认为,默认情况下,Solaris每个进程只允许256个文件句柄。对于服务器应用程序来说,特别是在专用服务器上运行时,这非常低。考虑到需要打开JRE和库JAR的50个或更多描述符,以及每个传入请求和数据库查询至少一个描述符,可能还需要更多,您可以看到这对于严肃的服务器来说根本不够。
请查看/etc/system
文件,了解rlim_fd_cur
和rlim_fd_max
的值,以查看系统设置如何。然后考虑这是否合理(您可以使用lsof
命令查看服务器运行时打开了多少文件描述符,最好使用-p [进程ID]参数)。
这是一种编程模式,可帮助找到未关闭的资源。它会关闭资源,并在日志中报告问题。
class
{
boolean closed = false;
File file;
close() {
closed = true;
file.close();
}
finalize() {
if (!closed) {
log error "OI! YOU FORGOT TO CLOSE A FILE!"
file.close();
}
}
将上述的 file.close() 调用包装在忽略错误的 try-catch 块中。
此外,Java 7 还有一个新的“try-with-resource”功能,可以自动关闭资源。