垃圾收集使FileDescriptor无效?

时间:2015-06-16 23:17:00

标签: android garbage-collection file-descriptor

我在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而不必担心与垃圾收集器竞争?

1 个答案:

答案 0 :(得分:3)

您没有保留对AssetFileDescriptor创建的openFd()的引用。当它获得GC时,它有一个内部ParcelFileDescriptor,最终也是GC。反过来,它会引用您在FileDescriptor调用中检索到的getFileDescriptor()。它也恰好有一个finalize()方法,当被调用时,将关闭文件描述符(通过调用IoUtils.closeQuietly(mFd);)。收集finalize()时,GC会调用此ParcelFileDescriptor方法。这就是您观察到的行为的发生方式。

我猜测为什么睡觉不会引发这些事件,因为GC没有压力要清理。

要测试此(并且,如果我是正确的,以防止失效),请在实验期间保持对openFd()返回的对象的引用。