2009-04-28 139 views
2

我刚刚开始了一项新工作。这里我们是使用JNI(桥接C++/Java)的新手。我是JNI的新手,所以请原谅我的noobness :)JNI与C++对象实例

在我们的(win32)Java应用程序中,我们正在加载一个C++ DLL。在Java方面,我们有几个“SomeJClass”实例,每个实例都需要访问DLL端的“SomeCClass”的相应实例。 该DLL公开入口点,如GlobalDoSomethingInC()。在这里我必须调用Doer :: DoSomethingInC()的实例方法。所以我需要一个平滑的方式来映射相应的这个指针。 当DLL线程发现一些有趣的事情需要通知相应的Java实例时,我也需要做同样的映射。

我可以想到几种解决方案,但我不太喜欢它们。我的问题是,有没有比这更好的方法?

1 Java调用C:GetNewInstance()。这将返回一个实际上是指向新C实例的指针的int。 Java将其存储在m_myCInstance中。然后Java调用GlobalDoSomethingInC(),和 1A

// DLL global 
void GlobalDoSomethingInC() 
{ 
    // retrive this pointer 
    //calling back to Java: 
    jobj tmpJ = NewGlobalRef(env, obj); 
    Doer* myDoer = <reinterpret_cast>(Doer)tmpJ->GetMyCInstance(); 
    myDoer->DoSomething(); 
    DeleteGlobalRef(env, tmpJ); 
    // Arrrrgh 
} 

1b或:

// for **every call** that Java adds a parameter, 
    //which is the stored int:m_myCInstance, and 
    Doer* myDoer = <reinterpret_cast>(Doer)instanceParam->DoSomethingInC(); 
    // Can we do better that this? 

2对于从C到Java的调用,事情看起来,也许,更好

In the constructor C calls back into Java and stores 
the Java instance reference 
    in a member variable. m_myJInstance. 
    In all subsequent calls m_myJInstance can be used to call back Java. 
    In the destructor we need to call DeleteGlobalRef(env, m_myJInstance); 

不是太不好,我想。但是存储jobject引用真的很安全。 我的意思是:当GC移动物体时会发生什么?

3我们现在的解决方案“工作”。但它属于上,而在http://www.codinghorror.com/blog/ :)

感谢名单

回答

2

通常,这将取决于你的环境有点。我只使用KNI,它比JNI更原始。我认为有一点丑陋是不可避免的,因为你在两个系统之间混合了内存跟踪,其中只有一个系统具有GC。

一般来说,我发现最好是将所有调用的C代码都包含在需要处理恶意代码的函数中,我认为这是不可避免的。 (顺便说一下,我将使用C来表示非Java代码)

在C方面,Java对象的移动肯定是一个潜在的问题。它将取决于你的平台,但我期望只要你在lib中,你就不会期望Java GC发生,所以你的对象是稳定的。你需要确定这一点。另一方面,如果情况并非如此,那么你几乎搞砸了。假设是这种情况,你希望将解引用/转换分离到暴露给JNI的函数中,以便你可以在所有被调用的函数中使用正常的C对象。

在哪里可以变得非常丑陋是因为如果你可以让对象在任何一边都超出范围,那么任何一方都可能持有对象的引用。这里我们使用了Java端的终结器,以及C端的析构器。这并不漂亮,但我认为这是不可避免的。

所以,简单的回答,它会有些丑陋,隔离两种语言之间界面的丑陋,因此对于大部分工作来说,无论使用哪种语言,您都不必担心这种事情。

在这个接口上存在的对象也有一个基类,因为在这里你也可以隔离一些丑陋。

0

jobject是一个对象的不透明手柄。在运行时实现中可能会有所不同(请参阅Android 2.x vs 4.x),但请相信它是不透明的对象。

目前的解决方案可能是正确的。如果您必须以本地代码存储jobject,则必须将其转换为全局引用 - 如果您调用NewGlobalRef,则该对象的引用计数已增加,并且在您调用DeleteGlobalRef之前不会处理(否则GC已注意到它无法访问)