Fortran 即使库被重新加载,JNA也会保持状态

Fortran 即使库被重新加载,JNA也会保持状态,fortran,jna,Fortran,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

我有一个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仍然存在于第二次调用中,即使库按照中的建议进行处理,如何避免这种情况


编辑:我使用的英特尔fortran编译器带有
-init:zero
,因此变量应该在引擎盖下用0重新初始化,JNA在加载
NativeLibrary
对象后保留对该对象的引用,除非显式调用
dispose()
,否则不会释放该对象

dispose()
方法包含在对象的
finalize()
中,该方法将在垃圾收集时调用,但是,不能依靠它始终执行。在您发布的代码片段中,将引用设为null,并使用单个
System.gc()
调用,这只是释放对象的建议。一个更好的选择是自己调用
dispose()


但是,如中所述,需要一个小的时间延迟来确保本机库在立即重新加载时不会返回相同的句柄。注意:OSX上至少有2毫秒的延迟,在您的评论中,您似乎在操作系统上成功地使用了10毫秒的延迟。

为什么要将x放在一个公共块中?我猜(我知道Fortran,不是java)这会导致您的问题,更不用说公共块在过去30年中不应该被使用。另外,使用x uninitialized会导致出现未定义的行为,因此事实上所有赌注都没有。@IanBush我正在处理一些遗留代码,不幸的是,这些代码大量使用了公共块。我知道x可以初始化为0,但我仍然感兴趣的是,如果我可以使用JNA解决这个问题,而不涉及本机代码,我不使用Intel的编译器,但会冒险猜测。当您使用
-init:zero
选项时,您可能还为所有已初始化的变量指定了“保存”属性。因此,Fortran编译器正提供您所要求的内容,即使它不是期望的结果。如果编译器选项更改了程序的语义,那就有点不太对劲了。在这里,我认为不是这样,我认为公共块中的变量会自动
save
d。所以
-init:zero
与OP的问题无关。@DanielWiddis我也尝试了您的选项2(调用
dispose()
),这会得到相同的结果。帮助的是在
System.gc
之后调用
Thread.sleep(10L)
。此外,删除编译器标志
-init:zero
也没有任何区别