当前位置: 首页 > 面试题库 >

文件描述符泄漏示例?

酆君墨
2023-03-14
问题内容

有没有很好的例子演示Android中的文件描述符泄漏?我读过某个地方,如果不关闭例如流,FileInputStream或者FileOutputStream我找不到任何能证明这一点的参考实例,就会发生这种情况。

请分享一些博客/代码段。谢谢!


问题答案:

由于Dalvik的 FileInputStream
会在被垃圾回收时自行关闭(对于OpenJDK
/
Oracle也是这样),因此它不如实际泄漏文件描述符那样普遍。当然,文件描述符将被“泄漏”,直到GC运行,因此取决于您的程序,可能需要一段时间才能收回它们。


为了实现更持久的泄漏,您必须通过在内存中的某个位置对其进行引用来防止对该流进行垃圾收集。

这是一个简短的示例,该示例每1秒加载一次属性文件,并跟踪每次更改的情况:

public class StreamLeak {

    /**
     * A revision of the properties.
     */
    public static class Revision {

        final ZonedDateTime time = ZonedDateTime.now();
        final PropertiesFile file;

        Revision(PropertiesFile file) {
            this.file = file;
        }
    }

    /*
     * Container for {@link Properties} that implements lazy loading.
     */
    public static class PropertiesFile {

        private final InputStream stream;
        private Properties properties;

        PropertiesFile(InputStream stream) {
            this.stream = stream;
        }

        Properties getProperties() {
            if(this.properties == null) {
                properties = new Properties();
                try {
                    properties.load(stream);
                } catch(IOException e) {
                    e.printStackTrace();
                }
            }
            return properties;
        }

        @Override
        public boolean equals(Object o) {
            if(o instanceof PropertiesFile) {
                return ((PropertiesFile)o).getProperties().equals(getProperties());
            }
            return false;
        }
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        URL url = new URL(args[0]);
        LinkedList<Revision> revisions = new LinkedList<>();
        // Loop indefinitely
        while(true) {
            // Load the file
            PropertiesFile pf = new PropertiesFile(url.openStream());
            // See if the file has changed
            if(revisions.isEmpty() || !revisions.getLast().file.equals(pf)) {
                // Store the new revision
                revisions.add(new Revision(pf));
                System.out.println(url.toString() + " has changed, total revisions: " + revisions.size());
            }
            Thread.sleep(1000);
        }
    }
}

由于延迟加载,我们将 InputStream 保留在 PropertiesFile中 ,每当我们创建新的 Revision
时都会将其保留,并且由于我们从不关闭流,因此此处将泄漏文件描述符。

现在,当程序终止时,操作系统将关闭这些打开的文件描述符,但是只要程序正在运行,它将继续泄漏文件描述符,如使用
lsof 可以看到的那样:

$ lsof | grep pf.properties | head -n 3
java    6938   raniz   48r      REG    252,0    0    262694 /tmp/pf.properties
java    6938   raniz   49r      REG    252,0    0    262694 /tmp/pf.properties
java    6938   raniz   50r      REG    252,0    0    262694 /tmp/pf.properties
$ lsof | grep pf.properties | wc -l    
431

而且,如果我们强制运行GC,则可以看到大部分返回:

$ jcmd 6938 GC.run
6938:
Command executed successfully
$ lsof | grep pf.properties | wc -l
2

剩下的两个描述符是存储在 Revision中 的描述符。

我在Ubuntu机器上运行了此程序,但是如果在Android上运行,则输出看起来类似。



 类似资料:
  • M Java应用程序可能存在文件描述符泄漏,因为我得到了异常。 我使用JFR运行应用程序,当我检查文件I/O时,几乎看不到任何I/O计数。是否可以使用JFR查找打开文件但不关闭文件的代码?

  • 文件描述符 Linux很重要的设计思想就是一切皆文件,网络是文件,键盘等外设也是文件,很神奇吧?于是所有资源都有了统一的接口,开发者可以像写文件那样通过网络传输数据,我们也可以通过/proc/的文件看到进程的资源使用情况。 内核给每个访问的文件分配了文件描述符(File Descriptor),它本质是一个非负整数,在打开或新建文件时返回,以后读写文件都要通过这个文件描述符了。 应用 我们想想操作

  • 文件描述符接口 函数 int  fd_new (void)   分配文件描述符   struct dfs_fd *  fd_get (int fd)   获取文件描述结构   void  fd_put (struct dfs_fd *fd)   放置文件描述符   int  fd_is_open (const char *pathname)   判断文件是否已被打开   int  select (

  • 问题内容: 有没有办法在原始文件描述符而不是FILE *上执行ftell()的操作(返回文件中的当前位置)?我认为应该有,因为您可以使用lseek()查找原始文件描述符。 我知道我可以使用fdopen()创建与文件描述符相对应的FILE *,但我宁愿不这样做。 问题答案: 只需使用:

  • 当使用了大量虚拟主机,而且每个主机又使用了不同的日志文件时,Apache可能会遭遇文件描述符(有时也称为文件句柄)耗尽的困境。Apache使用的文件描述符总数如下:每个不同的错误日志文件一个、每个其他日志文件指令一个、再加10-20个作为内部使用。Unix操作系统限制了每个进程可以使用的文件描述符数量。典型上限是64个,但可以进行扩充,直至到达一个很大的硬件限制为止(hard-limit)。 尽管

  • 处理文件描述符 尽管很不像,但是在大多操作系统中,标准输入输出流 stdin 和 stdout 虽然叫做「流」,但它们都有文件的接口。我们同样也会将它们实现成为文件。 但是不用担心,作为文件的许多功能,stdin 和 stdout 都不会支持。我们只需要为其实现最简单的读写接口。 进程打开的文件 操作系统需要为进程维护一个进程打开的文件清单。其中,一定存在的是 stdin stdout 和 std