Garbage Collection invalidates FileDescriptor?

a 夏天 提交于 2019-12-11 20:33:47

问题


I'm opening an asset using a FileDescriptor on Android. It appears that garbage collection changes the FileDescriptor's internal descriptor to -1. Attempting to use the FileDescriptor after that throws an exception.

As a sanity check, I added this code to a blank project:

    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);

This is the output

      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]

Why does this happen? How can I safely use a FileDescriptor without worrying about racing against the garbage collector?


回答1:


You aren't retaining a reference to the AssetFileDescriptor created by openFd(). When it gets GC'ed, it has an internal ParcelFileDescriptor that is also eventually GC'ed. That, in turn, has the reference to the FileDescriptor that you are retrieving in the call to getFileDescriptor(). It also happens to have a finalize() method that, when called, will close the file descriptor (by calling IoUtils.closeQuietly(mFd);). This finalize() method will be called by the GC when the ParcelFileDescriptor is collected. This is how the behavior you are observing happens.

My guess as to why sleeping doesn't trigger these events is that there's no pressure on the GC to clean things up.

To test this (and, if I'm right, to prevent the invalidation), maintain a reference to the object returned by openFd() for the duration of your experiment.



来源:https://stackoverflow.com/questions/30879831/garbage-collection-invalidates-filedescriptor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!