打开的文件句柄太多

gzjq41n4  于 2021-07-05  发布在  Java
关注(0)|答案(12)|浏览(625)

我正在开发一个巨大的遗留java应用程序,其中包含很多手写的东西,现在你可以让一个框架来处理这些东西。
我现在面临的问题是,solaris服务器上的文件句柄已经用完了。我想知道跟踪打开的文件句柄的最佳方法是什么?在哪里查看以及什么会导致打开的文件句柄耗尽?
我不能在solaris下调试应用程序,只能在我的windows开发环境下调试。在windows下分析打开的文件句柄是否合理?

sbtkgmzw

sbtkgmzw1#

当我需要测试ic计数时,这个小脚本帮助我保持打开文件的计数。如果是在linux上使用的,那么对于solaris您应该修补它(可能是:)


# !/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

你也可以试着玩jvmontion-xverify:none - 它应该禁用jar验证(如果大多数打开的文件是jars…)。对于通过未关闭的fileoutputstream进行的泄漏,您可以使用findbug(以上指导)或尝试查找如何修补标准java fileoutputstream/fileinputstream的文章,在这里您可以看到谁打开了文件,谁忘记了关闭它们。不幸的是,现在找不到这篇文章,但这是存在的:)还要考虑一下文件限制的增加-对于最新的*nix内核处理1024fd以上不是问题。

1aaf6o9v

1aaf6o9v2#

它肯定能给你一个主意。因为它是java,所以文件打开/关闭机制应该以类似的方式实现(除非其中一个jvm实现不正确)。我建议在windows上使用文件监视器。

xt0899hw

xt0899hw3#

我发现了一个跟踪未关闭文件句柄的好方法,那就是findbugs:
http://findbugs.sourceforge.net/
它检查许多事情,但其中最有用的是资源打开/关闭操作。它是一个在源代码上运行的静态分析程序,也可以作为eclipse插件使用。

neekobn8

neekobn84#

这是一种帮助查找未关闭资源的编码模式。它关闭资源,并在日志中抱怨问题。

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()调用 Package 到忽略错误的try catch块中。
另外,Java7有一个新的“try with resource”特性,可以自动关闭资源。

pvabu6sv

pvabu6sv5#

首先,我会要求我的系统管理员为进程获取所有打开的文件描述符的列表。不同的系统以不同的方式实现这一点:例如,linux具有 /proc/PID/fd 目录。我记得solaris有一个命令(可能是pfiles?)可以做同样的事情——您的系统管理员应该知道它。
但是,除非您看到对同一个文件的大量引用,否则fd列表不会对您有所帮助。如果它是一个服务器进程,那么它可能会因为某种原因打开很多文件(和套接字)。解决此问题的唯一方法是调整打开文件的系统限制—您也可以使用ulimit检查每个用户的限制,但在大多数当前安装中,该限制等于系统限制。

rqmkfv5c

rqmkfv5c6#

我会在你的solaris框中再次检查环境设置。我相信在默认情况下,solaris每个进程只允许256个文件句柄。对于服务器应用程序,尤其是在专用服务器上运行的应用程序,这是非常低的。图50或更多用于打开jre和库jar的描述符,然后至少为每个传入请求和数据库查询提供一个描述符,可能更多,您可以看到这不会减少严重服务器的负担。
看一看这个 /etc/system 文件,用于 rlim_fd_cur 以及 rlim_fd_max ,以查看系统设置了什么。然后考虑这是否合理(您可以看到服务器运行时打开了多少文件描述符) lsof 命令,最好使用-p[process id]参数。

pepwfjgg

pepwfjgg7#

从系统内部搜索名为filemon的应用程序。
顺便说一句,为了追踪这一点,您可以使用aspectj之类的工具来记录所有打开和关闭文件的调用,并记录它们发生的位置。

uplii1fm

uplii1fm8#

在windows上,可以使用process explorer查看打开的文件句柄:
http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx
在solaris上,可以使用“lsof”监视打开的文件句柄

muk1a3rh

muk1a3rh9#

在您的情况下,这可能不太实际,但当我在开放数据库连接方面遇到类似问题时,我曾经做过的是用我自己的函数覆盖“open”函数(方便的是,我已经有了这个函数,因为我们已经编写了自己的连接池。)然后在我的函数中,我向一个记录打开的表添加了一个条目。我做了一个堆栈跟踪调用,并保存了调用方的标识,以及调用的时间,我忘记了还有什么。当连接被释放时,我删除了表条目。然后我有了一个屏幕,我们可以转储打开的条目列表。然后您可以查看时间戳,很容易地看到哪些连接已经打开了不太可能的时间,哪些函数已经完成了这些打开。
从这一点上,我们能够快速跟踪到打开连接和关闭连接失败的两个函数。
如果您有许多打开的文件句柄,那么很有可能在某个地方完成操作时无法关闭它们。你说你已经检查了正确的try/finally块,但是我怀疑代码中的某个地方你要么漏掉了一个错误的块,要么你有一个函数,但从来没有到达finally。我想也有可能每次打开一个文件时都会进行适当的关闭,但同时打开的文件有数百个。如果是这样的话,我不知道你能做什么,除了一个严肃的程序重新设计来操作更少的文件,或一个严肃的程序重新设计来排队你的文件访问(在这一点上,我添加了通常的“不知道您的应用程序的细节等。)

kognpnkq

kognpnkq10#

值得记住的是,在unix系统上,opensocket还使用文件句柄。因此,很可能是数据库连接池泄漏(例如,打开的数据库连接未关闭并返回到池)导致了此问题-当然,我以前见过由连接池泄漏导致的此错误。

ecfsfe2w

ecfsfe2w11#

不是对您的问题的直接回答,但这些问题可能是由于在遗留代码中错误地释放文件资源而导致的。举例来说,如果使用fileoutputsstream类,请确保在finally块中调用close方法,如本例所示:

FileOutputsStream out = null;
try {
  //You're file handling code
} catch (IOException e) {
  //Handle
} finally {
  if (out != null) {
    try { out.close(): } catch (IOException e) { }
  }
}
wnvonmuf

wnvonmuf12#

回答问题的第二部分:
什么会导致打开的文件句柄耗尽?
很明显,打开了很多文件,却没有关闭它们。
最简单的情况是,对持有本机句柄的任何对象的引用(例如。, FileInputStream )在关闭之前被丢弃,这意味着文件在对象完成之前保持打开状态。
另一个选择是对象存储在某个地方,而不是关闭。堆转储可以告诉你什么东西在哪里逗留( jmap 以及 jhat 包含在jdk中,或者您可以使用 jvisualvm 如果您需要gui)。您可能对查找拥有的对象感兴趣 FileDescriptor s。

相关问题