文件描述符泄漏示例? [英] File descriptor leak example?

查看:199
本文介绍了文件描述符泄漏示例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Android中是否有任何好的示例来演示文件描述符泄漏?我在某处看到,如果我们不关闭流,例如 FileInputStream FileOutputStream ,就会发生这种情况,但我找不到任何一个很好的参考示例来演示它。

Is there any good example do demonstrate file descriptor leak in Android? I read somewhere that it occurs if we don't close the streams for example FileInputStream or FileOutputStream but I could not find any good reference example which demonstrates it.

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

Please share some blog/code snippet. thank you!

推荐答案

因为Dalvik的 FileInputStream close它本身是垃圾收集的(这对于OpenJDK / Oracle也是如此)它实际上泄漏文件描述符并不常见。当然,文件描述符将被泄露,直到GC运行,因此根据您的程序,它们可能需要一段时间才能被回收。

Because Dalvik's FileInputStream will close itself when it is garbage collected (this is also true for OpenJDK/Oracle) it is less common than you'd think to actually leak file descriptors. Of course, the file descriptors will be "leaked" until the GC runs so depending on your program it could take a while before they are reclaimed.

实现更长久的泄漏你必须通过在内存中的某个地方保持对它的引用来阻止流被垃圾收集。

To accomplish a more permanent leak you will have to prevent the stream from being garbage collected by keeping a reference to it somewhere in memory.

这是一个每1秒加载一个属性文件的简短示例每次更改时都会跟踪:

Here's a short example that loads a properties file every 1 second and keeps track of every time it has changed:

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 时都会保留它,因为我们从不关闭流,所以我们将泄漏文件描述符这里。

Because of the lazy loading we keep the InputStream in the PropertiesFile which will be kept whenever we create a new Revision and since we never close the stream we will be leaking file descriptors here.

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

Now, these open file descriptors will be closed by the OS when the program terminates, but as long as the program is running it will continue to leak file descriptors as can be seen by using 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运行我们可以看到最多其中包括:

And if we force the GC to run we can see that most of these are returned:

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

其余两个描述符是存储在中的描述符修订 s。

The remaining two descriptors are the ones stored in the Revisions.

我在我的Ubuntu机器上运行了这个,但如果在Android上运行,输出看起来会相似。

I ran this on my Ubuntu machine but the output would look similar if run on Android.

这篇关于文件描述符泄漏示例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆