gpt4 book ai didi

java - 文件描述符泄漏示例?

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:36:55 25 4
gpt4 key购买 nike

是否有任何好的示例可以证明 Android 中的文件描述符泄漏?我在某处读到,如果我们不关闭流,例如 FileInputStreamFileOutputStream,就会发生这种情况,但我找不到任何好的引用示例来演示它。

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

最佳答案

因为 Dalvik 的 FileInputStreamclose itself when it is garbage collected (对于 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 上运行,输出看起来会很相似。

关于java - 文件描述符泄漏示例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31237918/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com