Search code examples
fortranjna

JNA keeps state even if library is reloaded


I have a Fortran code which I try to wrap in a Java/Scala code. My issue is that the state of a variable in fortran is kept, even if I dispose the library between two calls:

Fortran-Code:

  subroutine mySub()
  implicit none  

  DOUBLE PRECISION x
  COMMON/myCommon/ x

  print*,x
  x = 99.99

  end subroutine mySub

And Java/Scala Code:

trait FortranLibrary extends Library {
 // native symbols
 def mysub_() 
}

def main(args: Array[String]): Unit = {

 var INSTANCE: FortranLibrary = Native.synchronizedLibrary(
  Native.load("sub.so", classOf[FortranLibrary])
 ).asInstanceOf[FortranLibrary]
 // call native subroutine
 INSTANCE.mysub_()

 println("------SECOND CALL-----")

 // clean library, reload
 INSTANCE = null
 System.gc()
 // make new instance
 INSTANCE = Native.synchronizedLibrary(
  Native.load(libpath, classOf[FortranLibrary])
 ).asInstanceOf[FortranLibrary]
 // call native subroutine
 INSTANCE.mysub_()
}

Prints to the console:

  0.000000000000000E+000
------SECOND CALL-----
   99.9899978637695  

So the previously set x=99.99 is still present in the second call even though the library is disposed as proposed in How to dispose library loaded with JNA , how can avoid this?

EDIT: I'm using intel fortran compiler with -init:zero, so variables should be re-initialized with 0


Solution

  • Under the hood, JNA keeps a reference to a NativeLibrary object once you've loaded it, and does not release it unless dispose() is explicitly called.

    The dispose() method is included in the object's finalize() which would be called upon garbage collection, however, this cannot be relied upon to always execute. In the code snippet you've posted, you null the reference and use a single System.gc() call, which is only a suggestion to release the object. A better option, which you've indicated in the comments that you've tried, is to call dispose() or disposeAll() yourself.

    However, as also noted in my answer to your linked question, a small time delay is needed to ensure the native library doesn't return the same handle if it's immediately reloaded. JNA source code notes at least a 2ms delay works on OSX, and in your comments it seems you've been successful on your OS with a 10ms delay.