【问题标题】:Java JNI: global variable collision in native codeJava JNI:本机代码中的全局变量冲突
【发布时间】:2010-03-02 07:40:21
【问题描述】:

晚安,大师们。假设我有一个 java 类 A:

class A {
    public A() {}
    public native void setValue(String value);
    public native String getValue();
}

在实现原生 C 代码时,使用一个全局 char[] 变量来存储刚刚被原生 setValue 方法设置的值。 getValue 方法只返回那个全局 char[] 变量。

我的问题来了:我创建了几个 A 对象,并调用它们各自的 set/get 方法,我发现它们最终写入和读取同一块内存!实际上 C 原生代码中的全局 char[] 变量是完全由所有 A 对象共享的。

谁能给我一些关于这种行为的深入解释?我知道我对 JNI 的工作方式存在根本性的误解。谢谢!

【问题讨论】:

    标签: java-native-interface


    【解决方案1】:

    问题是一方面是面向对象的 java,另一方面是过程 C。当加载一个 java 类 A 时,JNI 不会以某种方式在 C 世界中创建一个对象(这是 C - 不是 C++),没有对象到对象的映射。所以 JNI 将 C 世界中相应的 CPP 文件一次加载到内存中(这在 C 中是完全正常的行为)。编译器看到一堆函数和一个全局引用,不需要以某种方式创建多个实例。在加载 Java 类时,JNI 编译器所做的只是将 C 文件添加到要编译的文件列表中。

    您想要的是 Java 对象和 C 对象之间的映射。这可以通过多种方式实现,我建议您阅读 JNI 中的代理模式。

    简而言之,您有两种基本方法可以实现这一目标。您可以在 C 端或 Java 端执行此操作。在 C 世界中存储关系时,您将在 C 中维护一个哈希表,其中 C 对象映射到 Java 对象。反过来,您将在 Java 对象中有一个 int 对象,它实际上是指向内存中 C 对象的指针。在 C 代码中,您将取消引用该指针(通过 GetIntField())并转换为您需要的 C 对象。

    当然添加

    private String value;
    

    对于您的 Java 类 A,确实可以非常顺利地工作。 Java 有对象的概念,因此您可以使用

    从 C 世界中访问这些字符串
    env->GetObjectField(obj, "value", "Ljava/lang/String;")
    

    其中 env 是 JNI 环境。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多