垃圾收集使 FileDescriptor 无效?
Garbage Collection invalidates FileDescriptor?
我正在 Android 上使用 FileDescriptor 打开资产。似乎垃圾收集将 FileDescriptor 的内部描述符更改为 -1。之后尝试使用 FileDescriptor 会引发异常。
作为完整性检查,我将这段代码添加到一个空白项目中:
try{
fd = getAssets().openFd("greensleeves.wav").getFileDescriptor();
}catch(IOException e) {
}
System.out.println("file descriptor before gc" + fd);
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println("file descriptor before gc" + fd);
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println("file descriptor before gc" + fd);
System.gc();
System.out.println("file descriptor after gc" + fd);
System.out.println("file descriptor after gc" + fd);
System.out.println("file descriptor after gc" + fd);
这是输出
System.out I file descriptor before gcFileDescriptor[45]
System.out I file descriptor before gcFileDescriptor[45]
System.out I file descriptor before gcFileDescriptor[45]
dalvikvm D GC_EXPLICIT freed 176K, 3% free 9108K/9316K, paused 2ms+2ms, total 24ms
System.out I file descriptor after gcFileDescriptor[-1]
System.out I file descriptor after gcFileDescriptor[-1]
System.out I file descriptor after gcFileDescriptor[-1]
为什么会这样?我如何才能安全地使用 FileDescriptor 而不必担心与垃圾收集器竞争?
您没有保留对 openFd()
创建的 AssetFileDescriptor
的引用。当它被 GC 处理时,它有一个内部 ParcelFileDescriptor
最终也会被 GC 处理。反过来,它引用了您在调用 getFileDescriptor()
时检索的 FileDescriptor
。它也恰好有一个 finalize()
方法,调用时将关闭文件描述符(通过调用 IoUtils.closeQuietly(mFd);
)。当 ParcelFileDescriptor
被收集时,GC 将调用此 finalize()
方法。这就是您所观察到的行为的发生方式。
我猜测为什么睡眠不会触发这些事件是因为 GC 没有压力来清理东西。
为了对此进行测试(并且,如果我是对的,为了防止失效),请在实验期间维护对 openFd()
返回的对象的引用。
我正在 Android 上使用 FileDescriptor 打开资产。似乎垃圾收集将 FileDescriptor 的内部描述符更改为 -1。之后尝试使用 FileDescriptor 会引发异常。
作为完整性检查,我将这段代码添加到一个空白项目中:
try{
fd = getAssets().openFd("greensleeves.wav").getFileDescriptor();
}catch(IOException e) {
}
System.out.println("file descriptor before gc" + fd);
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println("file descriptor before gc" + fd);
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println("file descriptor before gc" + fd);
System.gc();
System.out.println("file descriptor after gc" + fd);
System.out.println("file descriptor after gc" + fd);
System.out.println("file descriptor after gc" + fd);
这是输出
System.out I file descriptor before gcFileDescriptor[45]
System.out I file descriptor before gcFileDescriptor[45]
System.out I file descriptor before gcFileDescriptor[45]
dalvikvm D GC_EXPLICIT freed 176K, 3% free 9108K/9316K, paused 2ms+2ms, total 24ms
System.out I file descriptor after gcFileDescriptor[-1]
System.out I file descriptor after gcFileDescriptor[-1]
System.out I file descriptor after gcFileDescriptor[-1]
为什么会这样?我如何才能安全地使用 FileDescriptor 而不必担心与垃圾收集器竞争?
您没有保留对 openFd()
创建的 AssetFileDescriptor
的引用。当它被 GC 处理时,它有一个内部 ParcelFileDescriptor
最终也会被 GC 处理。反过来,它引用了您在调用 getFileDescriptor()
时检索的 FileDescriptor
。它也恰好有一个 finalize()
方法,调用时将关闭文件描述符(通过调用 IoUtils.closeQuietly(mFd);
)。当 ParcelFileDescriptor
被收集时,GC 将调用此 finalize()
方法。这就是您所观察到的行为的发生方式。
我猜测为什么睡眠不会触发这些事件是因为 GC 没有压力来清理东西。
为了对此进行测试(并且,如果我是对的,为了防止失效),请在实验期间维护对 openFd()
返回的对象的引用。