Java 在JNI实现中创建静态全局变量是否不好?

Java 在JNI实现中创建静态全局变量是否不好?,java,c,performance,static,java-native-interface,Java,C,Performance,Static,Java Native Interface,我是JNI的新手,所以这个天真问题的答案可能是肯定的 目前的问题是,我正在实现一些C库的JNI绑定,以完成繁重的工作 在进行实际计算之前,C库需要首先从共享内存加载一个辅助数据结构(并返回指向“大”结构的指针),或者如果该结构在共享内存中不可用,则通过提供的路径从磁盘加载 辅助结构将用作常量 为了避免每次从磁盘加载,我考虑的是创建一个static int,表示大结构已正确初始化: static int big_struct_loaded_in_mem = 0; void Java_classN

我是JNI的新手,所以这个天真问题的答案可能是肯定的

目前的问题是,我正在实现一些C库的JNI绑定,以完成繁重的工作

在进行实际计算之前,C库需要首先从共享内存加载一个辅助数据结构(并返回指向“大”结构的指针),或者如果该结构在共享内存中不可用,则通过提供的路径从磁盘加载

辅助结构将用作
常量

为了避免每次从磁盘加载,我考虑的是创建一个
static int
,表示大结构已正确初始化:

static int big_struct_loaded_in_mem = 0;

void Java_className_dowork(/*parameters*/){
    if(!big_struct_loaded_in_mem){
        // load struct
        big_struct_loaded_in_mem = 1;
    }
    // load from shared mem then do work using big_struct
    load_from_shm();
}

void Java_className_cleanup(/*parameters*/){
    //free up mem
    big_struct_loaded_in_mem = 0;
}
为了简单起见,假设Java调用程序和本机函数是单线程的

多谢各位

注意:当然,没有
static int
的简单修复可能只是每次调用
load\u from\u shm()
,并测试返回的指针,但我很好奇这一特定想法是否不好:即在JNI绑定中生成静态全局变量

为了简单起见,假设Java调用程序和本机函数是单线程的

这就是问题所在。如果您需要从多个线程使用本机方法,该怎么办?如果它在你没有意识到的情况下发生了呢

JNI代码中的共享静态全局性本身并不坏,但建议您使其成为线程安全的。如果确实发生了线程安全问题,则可能会导致JVM硬崩溃,并且很难诊断

还建议执行一些Java端检查来管理数据结构的生命周期。例如,如果在“cleanup”方法之后调用“doWork”方法,则可能需要执行一些操作,以便抛出Java异常。或者使数据结构的加载成为一个单独的方法调用

更新

例如:

   public class BigStruct {
       static {
           // load native library
       }

       private static boolean loaded = false;
       private static boolean unloaded = false;

       private native boolean doLoad();
       private native boolean doUnload();
       private native void doComputation();

       public static synchronized void load() {
           if (loaded) {
               throw LoaderException("already loaded");
           }
           if (!doLoad()) {
               throw LoaderException("load failed");
           }
           loaded = true;
       }

       public static synchronized void unload() {
           if (unloaded) {
               throw LoaderException("already unloaded");
           }
           if (!doUnload()) {
               throw LoaderException("unload failed");
           }
           unloaded = true;
       }

       public static synchronized void computation(...) {
           if (!(loaded && !unloaded)) {
               throw LoaderException("wrong state");
           }
           doComputation(...);
       }
   }

是的,在JNI中应该避免全局静态

Java可以加载一个类的多个实例(例如,因为有多个类加载器),并且静态数据将在所有这些实例之间共享。不幸的是,如果类的一个实例被销毁,而另一个实例仍在使用中,那么cleanup调用也会导致不一致

在这些时候,使用本机类构造函数/终结器并分配/取消分配内存资源会更明智。这还允许使用不同的用例,例如不同的配置,具体取决于加载类的类加载器——例如在EJB应用程序容器中

为了简单起见,假设Java调用程序和本机函数是单线程的


错误的假设。JVM在幕后做很多事情。

谢谢Paul。真的从你的答案中学到了新的东西(类加载器)。谢谢你Stephen。真的很欣赏未来派的观点!但我不确定的一点是,如何在Java端检查C中加载的数据结构?我对JNI的理解是,JVM向本机库敞开了大门,让C代码获取它可以/需要的东西,而不是相反。因此,如果C端出了问题,Java端就不能做很多事情。