【问题标题】:JNI: Given jobject, obtain its cached methodJNI:给定jobobject,获取其缓存方法
【发布时间】:2013-02-11 21:50:24
【问题描述】:

在 Java 中,我有一个接口:

public interface I {...}

声明一个函数void f(),以及一些类:

public class A implements I {...}
public class B implements I {...}
public class C implements I {...}
...

我经常调用原生函数:

public native void nativeFunc(I obj);

在 C++ 中,我得到一个

jobject jobj

目的是调用

jobj.f();

无需每次都通过链条

cls = jenv->GetObjectClass(jobj);           (1)
mid = jenv->GetMethodID(cls, "f", "()V");   (2)
jenv->CallVoidMethod(jobj, mid);            (3)

我似乎无法在本地调用之间缓存mid。作为另一个建议,我可以从第 (1) 行开始,然后使用缓存的map <jclass, jmethodID>。但是,这也可能不起作用,因为同一类的 jclass 引用可能不同。

有什么优化方案吗?

【问题讨论】:

    标签: java c++ caching optimization java-native-interface


    【解决方案1】:

    我能想到的解决方案之一是通过 jclass 引用将类 A, B, C, ... 缓存到任何数据结构(数组、列表等;map 在这里没有加速)。我们称这个结构为 Storage。然后我可以优化步骤(2)并具有以下链:

    (1) ... (obtain jcls)
    (2) for(jclass jclsStored : Storage) {
            if(IsSameObject(jcls, jclsStored))
            {
                mid = ...;
                classFound = true;
            }
        }
        if(!classFound)
            Storage.add(necessary info);
    (3) ...            
    

    即我使用 JNI

    IsSameObject()
    

    函数为同一类绕过不同的jclass 值。如果IsSameObject() 很快,那么这就进行了优化。

    【讨论】:

      【解决方案2】:

      根据您的程序的性质和实现“接口 I”的类的数量,以及可用的类加载器的数量(可以乘以类的数量),您可以决定创建对这些类的全局引用

      jclass globalRefCls = jni->NewGlobalRef(localRefCls);
      

      然后您可以将这些实例和 jmethodID 缓存在映射中以供以后使用。

      更新

      在 cmets 演讲后,我重新阅读了您的要求。
      只要每次得到一个jobject,就需要把jclass弄出来反正,你的map也可以是map,其中字符串是类的描述符。

      每次你得到一个jobject,提取jclass并询问它的名字(你可以缓存java/lang/Class getName方法)。

      您也可以根据需要预先创建此缓存,因为您知道预期哪些对象(实现 I 的对象)

      话虽如此,我想它不会像检查 IsSameObject 那样有效。

      【讨论】:

      • Chen,如果您建议通过 jclass 引用缓存类 A, B, C...,那么它不会起作用,正如我在问题末尾所写的那样。在映射中缓存任何引用(本地或全局)都不好,因为对同一 Java 类/对象的不同引用可能在值上有所不同!
      • 为什么你认为缓存一个类的全局引用可能会有所不同?您是否使用可以卸载类的 VM?还是通过不同的类加载器加载多个类的虚拟机?
      • 阅读Android JNI tips的“本地和全局引用”部分下以“所有JNI方法接受...”开头的两段。
      • 这不适用于 jclass,因为如果不使用不同的类加载器,您无法创建两个相同类型的 Class 对象。
      • 恐怕这确实适用于课程。我刚刚进行了测试。我打了一个电话jclass c0 = jenv->GetObjectClass(jobj); 然后,我打了 100 个电话jclass c1 = jenv->GetObjectClass(jobj); 比较 (c0 == c1) 给出了错误(可能,对于所有 100 个案例),并且 IsSameObject(c0, c1) 给出了 true。这个测试是在一个原生函数中完成的,在它开始之后,作为一个代码块。
      猜你喜欢
      • 1970-01-01
      • 2020-04-19
      • 1970-01-01
      • 1970-01-01
      • 2023-03-07
      • 1970-01-01
      • 2019-11-07
      • 1970-01-01
      • 2012-11-09
      相关资源
      最近更新 更多