1

I am running calling a native function in Kotlin that takes a Unix file descriptor as a parameter. After the native function runs for a few minutes it report EBADF.

The code looks something like

class A(val file: ParcelFileDescriptor) : AutoCloseable {
    private var fileDes: Int = -1
    private external fun longRunningNativeFn(fd : Int) : FnResult

    init {
        fileDes = file.fd
    }
    
    fun process() : FnResult {
        longRunningNativeFn(fileDes)
    }
    override fun close {
    }
}

The file object passed into the constructor is not held anywhere else.

My working theory is that since file is only used in the init block, file then becomes a candidate for garbage collection so after a few minutes when the garbage collector kicks in, the file object calls close resulting in the native code getting a bad file descriptor.

So

  • is this theory correct?
  • If so what determines the lifetime of parameters in the constructor?
  • Does adding file.close() to the close function extend the lifetime of file for the duration of the class?

Note after adding the file.close(), I am no longer getting the BADF in my native code. Even though as @Ivo points out adding val to the primary constructor makes file a class member, the JRE might be smart enough to see nothing is using file and garbage collect it early since it needs to stick around until close is called

doron
  • 27,972
  • 12
  • 65
  • 103

1 Answers1

2

It's not merely a parameter of the constructor. You defined it as a property by writing val in front of it. You can access it throughout the entire lifetime of the instance. If you only want to have it as parameter you need to leave out the val like

class A(file: ParcelFileDescriptor) : AutoCloseable {

As for the lifetime if you write it like that, I personally don't know but I assume it gets garbage collected after the last init block but that's just a guess. And of course it also matters whether there are other references to that object outside of that class. I also have no idea why that EBADF happens

Ivo
  • 18,659
  • 2
  • 23
  • 35
  • 1
    When `file` is a field of the `A` instance, it prevents the garbage collection of the object referenced by `file`, as long as the `A` instance is reachable. So it all depends on how the `A` instance is used. Worth reading [Can java finalize an object when it is still in scope?](https://stackoverflow.com/q/24376768/2711488) and a similar related issue, [finalize() called on strongly reachable objects in Java 8](https://stackoverflow.com/q/26642153/2711488). In short, it’s possible that the `A` instance gets garbage collected even while the `process()` method is executed. – Holger Feb 15 '23 at 20:19
  • I have noted in my question, that adding the file.close() to the close function sorts the issue out, by I, guess ensuring file remains reachable for the duration – doron Feb 16 '23 at 14:02