持有JNI中本机类对象的引用

Holding reference to native class object in JNI

本文关键字:对象 引用 本机 JNI 持有      更新时间:2023-10-16

我正在尝试创建一个c++类并将其对象保存到一个数组中,并使用JNI从java引用这些c++对象,因为JNI没有提供任何机制来将任何非基本类型的对象保存到java中。

我已经实现了下面提到的代码,但是输出显示我好像已经创建了多个对象,并且在第二次调用创建新的本机对象时,我也收到了堆错误。

有人能调查一下吗?

感谢

代码:

Java类(加载库dll的函数已经在LibObj中定义):

package org.jnp.pkg004;
import org.jnp.libloader.LibObj;
public class PureCppObjFactory extends LibObj {
    private long cppobjlstsz;
    public PureCppObjFactory() {
        super();
        cppobjlstsz=0;
    }
    public native void newCppObj();
    public native void PrintCppObjDetails(long cppobjlstindex);
}
c++库代码:
#include "stdafx.h"
#include "stdlib.h"
#include <iostream>
#include <iomanip>
#include <stdio.h>
using namespace std;
#include "org_jnp_pkg004_PureCppObjFactory.h"
class NativeObjClass
{
    private:
        int num_ran;
        int obj_num;
    public:
        static int obj_cnt;
        NativeObjClass()
        {
            obj_cnt++;
            obj_num=obj_cnt;
            num_ran=rand();
            cout<<"Native Object number "<<setfill('0')<<setw(5)<<obj_cnt<<" Random number:"<<num_ran<<endl;    
        }
        int get_obj_num()
        {
            return obj_num;
        }
        int get_num_ran()
        {
            return num_ran;
        }
};
int NativeObjClass::obj_cnt=0;
NativeObjClass *nobj_lst;
long nobj_lst_size=0;
JNIEXPORT void JNICALL Java_org_jnp_pkg004_PureCppObjFactory_newCppObj
  (JNIEnv *env, jobject obj)
{
    jclass thisCls = env->GetObjectClass(obj);
    jfieldID fid=env->GetFieldID(thisCls,"cppobjlstsz","J");    
    NativeObjClass nobj;
    jlong java_lst_sz=env->GetLongField(obj,fid);   
    NativeObjClass *temp_nobj_lst;
    temp_nobj_lst=new NativeObjClass[nobj_lst_size];
    if(nobj_lst_size>0)
    {
        memmove(temp_nobj_lst,nobj_lst,nobj_lst_size);
        delete nobj_lst;
    }   
    nobj_lst_size++;
    nobj_lst=new NativeObjClass[nobj_lst_size];
    if(nobj_lst_size>1)
    {
        memmove(nobj_lst,temp_nobj_lst,nobj_lst_size);
        delete temp_nobj_lst;
    }
    nobj_lst[nobj_lst_size]=nobj;
    java_lst_sz++;
    env->SetLongField(obj,fid,java_lst_sz);
}

JNIEXPORT void JNICALL Java_org_jnp_pkg004_PureCppObjFactory_PrintCppObjDetails
  (JNIEnv *env, jobject obj, jlong indx)
{
    NativeObjClass nobj=nobj_lst[indx];
    cout<<"Retrieved Native Object number "<<setfill('0')<<setw(5)<<nobj.get_obj_num()<<" Random number:"<<nobj.get_num_ran()<<endl;
}

类包含main:

package test.jnp.pkg004;
import org.jnp.pkg004.PureCppObjFactory;
public class PureCppObjFactoryTest {
    public static void main(String[] args) {
        PureCppObjFactory pcf=new PureCppObjFactory();
        pcf.newCppObj();
        pcf.PrintCppObjDetails(0);
        pcf.newCppObj();
        //pcf.newCppObj();
    }
}
输出:

Native Object number 00001 Random number:41
Native Object number 00002 Random number:18467
Retrieved Native Object number 00002 Random number:18467
Native Object number 00003 Random number:6334
Native Object number 00004 Random number:26500

也得到堆错误弹出后,这段代码执行

好,下面是第一眼看到的问题列表:

  • using namespace std;是不良形式
  • static int obj_cnt;不是线程安全的
  • NativeObjClass *nobj_lst;应该是静态成员
  • NativeObjClass *nobj_lst;应该是std::vector
  • long nobj_lst_size=0;应该是静态成员
  • long nobj_lst_size=0;应该是size_t类型
  • NativeObjClass nobj;创建一个对象-它不仅仅是一个引用
  • nobj_lst=(NativeObjClass*)calloc(nobj_lst_size,sizeof(NativeObjClass));是完全错误的。如果必须使用手动管理的数组,请使用new[],但std::vector仍然更好
  • nobj_lst[nobj_lst_size-1]=nobj复制您创建的对象
  • NativeObjClass nobj=nobj_lst[indx];复制你的数组对象

可以考虑这种方法。请注意,下面的代码没有经过测试,甚至没有编译,它只是为了显示这个想法。

public class CppObject {
    private long handle;
    public CppObject() {
        handle = createNativeObject();
    }
    public void cleanup() {
        deleteNativeObject(handle);
        handle = 0;
    }
    private static native long createNativeObject();
    private static native void deleteNativeObject(long handle);
    private static native void printObjectDetails(long handle);

    public void PrintObjDetails() {
        printObjectDetails(handle);
    }
}


JNIEXPORT jlong JNICALL whatever_createNativeObject(JNIEnv *env, jobject obj) {
    return reinterpret_cast<jlong>(new CppObject());
}
JNIEXPORT void JNICALL whatever_deleteNativeObject(JNIEnv *env, jobject obj, jlong handle) {
    delete reinterpret_cast<CppObject *>(handle);
}
JNIEXPORT void JNICALL printObjectDetails(JNIEnv *env, jobject obj, jlong handle) {
    reinterpret_cast<CppObject *>(handle)->printDetails();
}

java long是64位的,所以上面的代码在32位和64位平台上都可以正常工作。

#include "stdafx.h"
#include "stdlib.h"
#include <iostream>
#include <iomanip>
#include <stdio.h>
using namespace std;
#include "org_jnp_pkg004_PureCppObjFactory.h"
class NativeObjClass
{
    private:
        int num_ran;
        int obj_num;
    public:
        static int obj_cnt;
        NativeObjClass()
        {
            obj_cnt++;
            obj_num=obj_cnt;
            num_ran=rand();
            cout<<"Native Object number "<<setfill('0')<<setw(5)<<obj_cnt<<" Random number:"<<num_ran<<endl;    
        }
        int get_obj_num()
        {
            return obj_num;
        }
        int get_num_ran()
        {
            return num_ran;
        }
};
int NativeObjClass::obj_cnt=0;
NativeObjClass *nobj_lst;
long nobj_lst_size=0;
JNIEXPORT void JNICALL Java_org_jnp_pkg004_PureCppObjFactory_newCppObj
  (JNIEnv *env, jobject obj)
{
    jclass thisCls = env->GetObjectClass(obj);
    jfieldID fid=env->GetFieldID(thisCls,"cppobjlstsz","J");    
    NativeObjClass nobj;    
    jlong java_lst_sz=env->GetLongField(obj,fid);       
    if(nobj_lst_size==0)
    {           
        nobj_lst_size++;
        nobj_lst=(NativeObjClass*)calloc(nobj_lst_size,sizeof(NativeObjClass));     
        nobj_lst[nobj_lst_size-1]=nobj;
    }   
    else
    {
        nobj_lst_size++;
        nobj_lst=(NativeObjClass*)realloc(nobj_lst,nobj_lst_size*sizeof(NativeObjClass));   
        nobj_lst[nobj_lst_size-1]=nobj;
    }   
    java_lst_sz++;
    env->SetLongField(obj,fid,java_lst_sz);
}

JNIEXPORT void JNICALL Java_org_jnp_pkg004_PureCppObjFactory_printCppObjDetails
  (JNIEnv *env, jobject obj, jlong indx)
{
    NativeObjClass nobj=nobj_lst[indx];
    cout<<"Retrieved Native Object number "<<setfill('0')<<setw(5)<<nobj.get_obj_num()<<" Random number:"<<nobj.get_num_ran()<<endl;
}