首页 > 解决方案 > 即使重新加载库,JNA 也会保持状态

问题描述

我有一个 Fortran 代码,我尝试将其包装在 Java/Scala 代码中。我的问题是保留了 fortran 中变量的状态,即使我在两次调用之间处理了库:

Fortran 代码:

  subroutine mySub()
  implicit none  

  DOUBLE PRECISION x
  COMMON/myCommon/ x

  print*,x
  x = 99.99

  end subroutine mySub

和 Java/Scala 代码:

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_()
}

打印到控制台:

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

因此,先前设置的 x=99.99 仍然存在于第二次调用中,即使按照How to dispose library loaded with JNA中的建议处理了库,如何避免这种情况?

编辑:我使用 intel fortran 编译器-init:zero,所以变量应该用 0 重新初始化

标签: fortranjna

解决方案


NativeLibrary在后台,一旦你加载了一个对象,JNA 就会保留一个对它的引用,并且除非dispose()被显式调用,否则它不会释放它。

dispose()方法包含在finalize()将在垃圾收集时调用的对象中,但是不能依赖此方法始终执行。在您发布的代码片段中,您将引用设为空并使用单个System.gc()调用,这只是释放对象的建议。您在尝试过的评论中指出,一个更好的选择是打电话dispose()disposeAll()自己打电话。

但是,正如我在对您的链接问题的回答中所指出的那样,需要一点时间延迟来确保本机库在立即重新加载时不会返回相同的句柄。 JNA 源代码指出在 OSX 上至少有 2 毫秒的延迟,在您的评论中,您似乎在 10 毫秒延迟的情况下在您的操作系统上取得了成功。


推荐阅读