0

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

Raphael Roth
  • 26,751
  • 15
  • 88
  • 145
  • Why have you put x in a common block? I would guess (I know Fortran, not java) that this causing your problems, not to mention common blocks shouldn't have been used in the last 30 years. Also using x uninitialised has caused undefined behaviour to occur, so in fact all bets are off. – Ian Bush Mar 19 '20 at 15:27
  • @IanBush I'm working with some legacy code which makes extensive use of common-blocks, unfortunately. I know that x could be initialized to 0, but I'm still interested if I could solve this using JNA without touching the native code – Raphael Roth Mar 19 '20 at 15:31
  • I don't use Intel's compiler, but will hazard a guess. When you use the `-init:zero` option, you likely are also giving all variables that become initialized, the `SAVE attribute. So, the Fortran compiler is giving you exactly what you requested even though it is not the desired result. – evets Mar 19 '20 at 16:40
  • It would be a bit naughty if a compiler option changed the semantics of a program. Here, I don't think it does, I think that variables in common blocks are automatically `save`d. So `-init:zero` has nothing to do with OP's problem. – High Performance Mark Mar 19 '20 at 19:25
  • `System.gc()` is only a suggestion to collect garbage, it's not a guarantee. Executing it twice would improve your chances but still not guarantee it. You should [explicitly `dispose()` your library if you don't want it](https://stackoverflow.com/a/41090490/1161484). – Daniel Widdis Mar 19 '20 at 20:48
  • Of note, you say "even though the library is disposed as proposed in...." my answer linked in the previous comment. However, you did not do so. You used Option 1 which clearly says it is not guaranteed to force programmatic behavior on reloading. Option 2 or 3 would be preferred, plus a small time delay. – Daniel Widdis Mar 19 '20 at 20:52
  • @HighPerformanceMark, what exactly fo you think `-init:zero` is doing? It is changing the semantics of the program! If `-init:zero` is treated as-if an uninitialized variable were within a `DATA` statement or an initialization expression, then the variable **implicitly acquires** the `SAVE` attribute. As this option is non-standard, one needs to read the documentation of the compiler in question. – evets Mar 19 '20 at 21:58
  • 1
    @DanielWiddis I also tried your Option 2 (calling `dispose()`), this gives the same result. What did help is to call `Thread.sleep(10L)` after `System.gc`. Also, removing compiler flags `-init:zero` did not make any difference – Raphael Roth Mar 20 '20 at 05:58
  • Try doing it without the common block to see if that helps. If it does then the problem might be that *"Data in a common block is preserved if the common block is also declared in the main program (or in another subprogram that is in execution)."* I do not understand the JAVA/SCALA code but it is possible that the instance of `FortranLibrary` keeps the common block definition alive and this causes the data in it to be persistent. – PetrH Mar 20 '20 at 13:51
  • So do I understand the 10ms time delay after the dispose worked? If so I can post that as an answer. – Daniel Widdis Mar 20 '20 at 16:28

1 Answers1

0

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.

Daniel Widdis
  • 8,424
  • 13
  • 41
  • 63