JNI简易开发

JNI简易开发

Whg,20210324

1 基础配置

Oracle官方文档:

https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html

其他参考:

https://www.eg.bucknell.edu/~mead/Java-tutorial/native1.1/TOC.html#invoking

1.1 JDK

n  javac,将java文件编译成.class文件

n  javah,使用class文件生成JNI头文件h使用

n  javap,反编译器。解析class文件,输出编译信息

n  java,在jvm上运行java文件和class文件

1.2 g++、gdb、clion

       sudo apt install g++

       c++编译器,调试器

1.3 native开发使用到的jni头文件

 

2 基础介绍

2.1 java基础

        此外,还应注意java的垃圾回收机制,这会影响到jni Function的不同调用。

2.1.1 对c++的要求

       由于jvm是多线程的,native要求被编译成支持多线程,以支持jvm多线程特性

2.2 JNI基础

 

This chapter introduces the Java Native Interface (JNI). The JNI is a native programming interface. It allows Java code that runs inside a Java Virtual Machine (VM) to interoperate with applications and libraries written in other programming languages, such as C, C++, and assembly.

JNI基于jvm特性实现了java和native的互通操作,其互通操作分为2种类型:

l  JNI function,用于在java和native之间实现功能上的互通。提供了对java field、method、static等域的操作

l  Invocation API,实现了native与jvm的互通

2.2 JNI设计概览

2.2.1 JNI function

       JNI function被设计成类似c++ virtual table的二级指针结构,JNI function有以下特点:

l  JNI interface pointer内部维护了functions table,指向具体的JNi function实现

l  JNI interface pointer与线程绑定,不可跨线程访问,其使用thread-local特性实现

l  JNI interface pointer 作为native 方法的参数传入

l  Jvm保证,单线程中的多个native 方法的JNI interface pointer一致,多线程中的native方法收到的JNI interface pointer不一致

 

该设计的优点:

l  该设计具有很高的灵活度,与native的实现完全剥离

l  比如,一个jvm可以同时拥有多个JNI interface pointer的内部实现(function table),而native代码,完全不必关心JNI interface pointer内部function table的组织结构

 

JNI interface pointer的代码示例(二级指针表的结构):

 

2.2.2 Invocation API

       Invocation API主要用作native method操作jvm,因jvm负责整体环境,所以Invocation API涉及了一些环境上的操作,如:

l  创建、销毁jvm

l  将线程与jvm注册、分离

2.2.3 JNI libraries

l  jint JNI_OnLoad(JavaVM *vm, void *reserved);

当java加载so时,jvm会调用JNI_OnLoad。JNI_OnLoad必须返回当前使用的JNI版本号,jvm对返回的版本号进行识别,指定JNI的具体实现。所以,有必要了解一下不同jni版本号的功能特性

如果native不实现JNI_OnLoad,则jvm默认版本为JNI_VERSION_1_1

如果native实现了JNI_OnLoad但返回的版本号无效,则so会加载失败

 

附:Changes in JNI 1.1.2

 

l  void JNI_OnUnload(JavaVM *vm, void *reserved);

当java加载so的class loader被垃圾回收后,jvm才调用OnUnload。该函数可用于清理native的缓存

 

下图是JNI_OnLoad、JNI_OnUnload在JNI library中的定义,以及JDK8支持支持的JNI版本类型,高16字节是大版本,低16字节是小版本

 

3 JNI基础类型和数据结构

3.1 基础类型映射

3.2 JNI reference type

       Java数据类型,除了基础数据类型外,别的几乎都是object的子类。对于java object对象,obj1 = ojb2,相当于c++ 传递reference or pointer,而非assign or construct。

3.2.1 LocalReference

局部对象引用仅存活在native method方法期间,return后自动释放referfence

如若native method占用时间太长,大对象无法得到及时释放,此时,需要显示使用DeleteLocalRef释放局部对象

3.2.2 GlobalReference

全局对象由NewGlobalRef从局部对象或者全局对象产生,局部对象只在显示调用DeleteGlobalRef后才会销毁

3.2.3 WeakReference

       WeakReference也是一种全局引用,但与GlobalReference的区别在于,weakReference指向的对象,可能会被垃圾收集器回收。

3.2.4 IsSameObject

       以上对象引用,均可以使用jbool IsSameObject(Obj1, Obj2); 判断对象引用是否有效(与NULL对比)

3.3 field id

 

3.4 method id

 

3.5 function argument array value type

 

该类型用作native调用java方法的参数列表类型使用,如

 

3.6 Type Signatures

3.6.1 argument signature

Java的filed和method都有类型签名,native调用java方法时,必须告知jvm的java method 的name和signatures,以便jvm查找到java 方法。

Java类型签名的定义:

 

可以使用javap -s参数进行查看。如:

 

3.6.2 native method signature

Java方法名称:

private native String sayHello(String msg);

由javah生成的native方法:

/*

 * Class:     HelloJNI

 * Method:    sayHello

 * Signature: (Ljava/lang/String;)Ljava/lang/String;

 */

JNIEXPORT jstring JNICALL Java_HelloJNI_sayHello (JNIEnv *, jobject, jstring);

 

Native方法名的格式如下:

l  前缀Java_

l  完整的包名HelloJNI_

l  方法名sayHello

l  如果是重载的方法,两个下划线__后紧跟参数签名

 

对于下面的方法:

class Cls1 {

  int g(int i);

  native int g(double d);

}

上述的native method g并不属于重载,因为另外一个g不是native方法

3.7 Modified UTF-8 Strings

       JNI使用修改后的UTF8格式(非标准UTF8格式)。所以,需要使用GetStringUTFChars等方法转成c++ 的string。

也可以使用GetStringUTFLength查询UTF8的长度。

4 library 操作

见2.2.3

4.1 JNI_OnLoad

       jint JNI_OnLoad(JavaVM *vm, void *reserved)

4.2 JNI_OnUnload

void JNI_OnUnload(JavaVM *vm, void *reserved)

5 jvm操作

5.1 GetEnv

       通过jvm获取当前线程的env

5.2 GetJavaVM

       通过jenv获取jvm

5.3 AttachCurrentThread

5.4 DetachCurrentThread

       JNI function与线程环境挂钩,如果native方法回调java方法时

l  已保存当前线程的JNIEnv,则使用当前线程的env调用JNI Function

l  如果未保存当前线程的JNIEnv(不考虑是主线程还是主线程),则使用GetEnv获取当前线程的JNIEnv,再执行JNI Function操作

l  使用完后,可以解除与线程的绑定。或者保存,供下次子线程调用

 

子线程attach、detach的大致过程为:

 1 ...
 2 
 3 std::thread::id currentThreadId = std::this_thread::get_id();
 4     if (mainThreadId_.load() == currentThreadId) {
 5         DLOG(INFO) << "shell thread : async result using main thread : " <<  std::hex << currentThreadId;
 6         SyncResultCallback(queryText, results, candidateStartIndex, flag, highLightIndex);
 7         return;
 8     }
 9 
10     if (jvm_ == nullptr) {
11         DLOG(ERROR) << "shell thread : " <<  std::hex << currentThreadId << " global JavaVM is invalid ";
12         return;
13     }
14     JNIEnv* env {nullptr};
15     jint jresult = jvm_->GetEnv((void**)&env, global_jni_version);
16 //    if (jresult != JNI_OK || env == nullptr) {
17 //        return;
18 //    }
19 
20     jresult = jvm_->AttachCurrentThread(&env, NULL);
21     if (jresult != JNI_OK) {
22         DLOG(ERROR) << "thread : " <<  std::hex << currentThreadId << std::dec << ", AsyncResultCallback : cannot attach current thread, error code " << jresult;
23         return;
24     }
25 
26 ...    do something ...
27 
28 jresult = jvm_->DetachCurrentThread();
29     if (jresult != JNI_OK) {
30         DLOG(ERROR) << "shell thread : " <<  std::hex << std::this_thread::get_id() << std::dec << ", AsyncResultCallback : cannot detach current thread, error code " << jresult;
31         return;
32     }
33 
34 ...

 

6 JNI操作

6.1 java调用native方法

       Java代码直接调用即可

6.2 native操作reference

       详细介绍见3.2节

 

l  NewGlobalRef

l  DeleteGlobalRef

l  DeleteLocalRef

l  EnsureLocalCapacity

l  PushLocalFrame

l  PopLocalFrame

l  NewLocalRef

l  NewWeakGlobalRef

l  DeleteWeakGlobalRef

 

6.3 native访问java field

如访问:

 

 

 

实现步骤:

  1. 使用GetObjectClass(thisObj)获取jclass
  2. 使用GetFieldID(jclass, filed name, field signature)获取jfieldid
  3. 使用GetObjectField(object, fieldid)获取field的值

l  GetFieldID

l  Get<type>Field Routines

l  Set<type>Field Routines

 

l  GetStaticFieldID

l  GetStatic<type>Field Routines

l  SetStatic<type>Field Routines

6.4 native访问java method

如native访问java的方法

实现步骤:

  1. 使用GetObjectClass(thisObj)获取jclass
  2. 使用GetMethodId(jclass, method name,method signature)获取jmethodid
  3. 使用CallMethodID(object, methodid, argument)访问method

l  Call<type>Method Routines

l  Call<type>MethodA Routines,

l  Call<type>MethodV Routines

 

l  CallNonvirtual<type>Method Routines

l  CallNonvirtual<type>MethodA Routines

l  CallNonvirtual<type>MethodV Routines

 

l  GetStaticMethodID

l  CallStatic<type>Method Routines

l  CallStatic<type>MethodA Routines

l  CallStatic<type>MethodV Routines

6.5 native操作jstring

l  NewString

l  GetStringLength

l  GetStringChars

l  ReleaseStringChars

l  NewStringUTF

l  GetStringUTFLength

l  GetStringUTFChars

l  ReleaseStringUTFChars

l  GetStringRegion

l  GetStringUTFRegion

l  GetStringCritical

l  ReleaseStringCritical

6.6 native操作jarray

l  GetArrayLength

l  NewObjectArray

l  GetObjectArrayElement

l  SetObjectArrayElement

l  New<PrimitiveType>Array Routines

l  Get<PrimitiveType>ArrayElements Routines

l  Release<PrimitiveType>ArrayElements Routines

l  Get<PrimitiveType>ArrayRegion Routines

l  Set<PrimitiveType>ArrayRegion Routines

l  GetPrimitiveArrayCritical

l  ReleasePrimitiveArrayCritical

6.7 native操作java exception

l  Throw

l  ThrowNew

l  ExceptionOccurred

l  ExceptionDescribe

l  ExceptionClear

l  FatalError

l  ExceptionCheck

6.8 native访问java class

l  DefineClass

l  FindClass

l  GetSuperclass

l  IsAssignableFrom

6.9 native操作java object

l  AllocObject

l  NewObject, NewObjectA, and NewObjectV

l  GetObjectClass

l  GetObjectRefType

l  IsInstanceOf

l  IsSameObject

6.10 java操作native class

一般流程:

1:通过static native方法创建native类实例,将native 类地址(int)返回给java

2:native同时提供出带指针地址的方法

3:java调用步骤2的native方法,将1中获取的类地址作为参数传递

4:native方法收到类地址时,使用类型转换将地址转为class类型,紧跟调用类对应方法

如下所示,nativeInterface为native创建的类地址

 1 JNI_GENERATOR_EXPORT jboolean
 2     Java_com_Interface_nativeNMethod(JNIEnv* env, jobject
 3     jcaller,
 4     jlong nativeInterface,
 5     jstring languageToken) {
 6   Interface* native = reinterpret_cast<Interface*>(nativeInterface);
 7   CHECK_NATIVE_PTR(env, jcaller, native, "NMethod", false);
 8   return native->NMethod(env, base::android::JavaParamRef<jobject>(env,
 9       jcaller), base::android::JavaParamRef<jstring>(env,param));
10 }

 

7 JNI测试-HelloJNI为例

 

源文件HelloJNI.java:

 1 import java.util.Scanner;
 2 
 3 public class HelloJNI {  // Save as HelloJNI.java
 4    static {
 5       System.load("/mnt/hgfs/workspace/self/java/jni/libHelloJNI.so"); // Load native library hello.dll (Windows) or libhello.so (Unixes)
 6                                    //  at runtime
 7                                    // This library contains a native method called sayHello()
 8    }
 9 
10    final static int integer = 1;
11    final private String string = "abc";
12    // Declare an instance native method sayHello() which receives no parameter and returns void
13    private native String sayHello(String msg);
14    private native void callbackEntry(String msg);
15    private native void getJavaFiled();
16    private native void localReference();
17    private native void localReferenceRelease();
18    private native void globalReference();
19    private native void globalReferenceRelease();
20    private native void weakGlobalReference();
21    private native void weakGlobalReferenceRelease();
22    private native void arraySum(int[] array);
23    private native void catchThrow() throws IllegalArgumentException;
24 
25    // Test Driver
26    public static void main(String[] args) {
27     HelloJNI helloJNI = new HelloJNI();
28 
29     Scanner input = new Scanner(System.in);
30     String val = input.next();
31     do {
32         if (val != null) {
33             if (val.equals("callJavaMethod")) {
34                 // call java method
35                 helloJNI.callbackEntry("callbackEntry from java");
36             } else if (val.equals("getJavaField")) {
37                 // access java member variables
38                 helloJNI.getJavaFiled();
39             } else if (val.equals("catchThrow")) {
40                 boolean exceptionOccur = false;
41                 // catch and throw exception
42                 try {
43                     helloJNI.catchThrow();
44                 }
45                 catch(Exception e) {
46                     exceptionOccur = true;
47                     System.out.println("catch native exception, show call stack");
48                     e.printStackTrace();
49                 }
50                 finally {
51                     //
52                     if (exceptionOccur) {
53                         System.out.println("recover from exception");
54                     }
55                 }
56             } else if (val.equals("localReference")) {
57                 helloJNI.localReference();
58             } else if (val.equals("localReferenceRelease")) {
59                 helloJNI.localReferenceRelease();
60             } else if (val.equals("globalReference")) {
61                 helloJNI.globalReference();
62             } else if (val.equals("globalReferenceRelease")) {
63                 helloJNI.globalReferenceRelease();
64             } else if (val.equals("weakReference")) {
65                 helloJNI.weakGlobalReference();
66             } else if (val.equals("weakReferenceRelease")) {
67                 helloJNI.weakGlobalReferenceRelease();
68             } else if (val.equals("arraySum")) {
69                 helloJNI.arraySum(new int[]{1,2,3,4,5,6});
70             } else {
71                 // Accessing Java Strings
72                 String str = helloJNI.sayHello(val);
73                 System.out.println("return native str : " + str);
74             }
75         }
76         System.out.println("-------------------------------------------------");
77         val = input.next();
78     } while(!val.equals("exit"));
79     input.close();
80    }
81 
82    private String CallbackByNative(String str, int strLength) {
83         return "native str callback: " + str + ", length :" + Integer.toString(strLength);
84    }
85 
86    private void catchThrowByJava() throws NullPointerException {
87        throw new NullPointerException("thrown in CatchThrow.callback");
88      }
89 }

 

源文件Hello JNI.cpp

  1 #include <iostream>    // C++ standard IO header
  2 #include "HelloJNI.h"  // Generated
  3 #include <cstring>
  4 using namespace std;
  5 
  6 //JNIEXPORT jstring JNICALL NativeCallJavaMethod(JNIEnv *env, jobject thisObj, const char* str) {
  7 //    // get java class name
  8 //    jclass cls = env->GetObjectClass(thisObj);
  9 //    // use class method by class name, method name, signature
 10 //    jmethodID jmethodId = env->GetMethodID(cls, u8"CallbackByNative", u8"(Ljava/lang/String;I)Ljava/lang/String;");
 11 //    if (jmethodId == NULL) {
 12 //        return NULL;
 13 //        // method not found
 14 //    }
 15 //    // new native str
 16 //    size_t strLength = std::strlen(str);
 17 //    char* newStr = new char[strLength + 1];
 18 //    memcpy(newStr, str, strLength);
 19 //    memset(newStr + strLength, 0, 1);
 20 //    jstring newJavaStr = env->NewStringUTF(newStr);                     // new string
 21 //    // call java method by object, method, params
 22 //    jstring javaResult = (jstring)env->CallObjectMethod(thisObj, jmethodId, newJavaStr, strLength);
 23 //    // jstring to native str
 24 //    char* nativeStr = (char*)env->GetStringUTFChars(javaResult, NULL);    // native str trans from java string
 25 //    printf("result str from java callback : %s\n", nativeStr);
 26 //    env->ReleaseStringUTFChars(javaResult, nativeStr);
 27 //    delete [] newStr;
 28 //}
 29 
 30 // In order to use any of the new JNI functions, a native library must export a JNI_OnLoad function that returns JNI_VERSION_1_2.
 31 // If the native library does not export a JNI_OnLoad function, the VM assumes that the library only requires JNI version JNI_VERSION_1_1.
 32 JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
 33     JNIEnv* env = NULL;
 34     jint ret = vm->AttachCurrentThread(reinterpret_cast<void **>(&env), NULL);
 35     printf("JNI_OnLoad\n");
 36     std::flush(std::cout);
 37     return JNI_VERSION_1_6;
 38 }
 39 
 40 JNIEXPORT void JNI_OnUnload(JavaVM *vm, void *reserved) {
 41     printf("JNI_OnUnload\n");
 42     std::flush(std::cout);
 43 }
 44 
 45 // Implementation of the native method sayHello()
 46 JNIEXPORT jstring JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject thisObj, jstring jstr) {
 47     // get jni version
 48     jint version = env->GetVersion();
 49     // get java str length(UTF8)
 50     jsize jstrLeng = env->GetStringLength(jstr);                    // str length
 51     jsize jstrLengUTF8 = env->GetStringUTFLength(jstr);             // str UTF8 length : if char is chinese, UTF8length = length * 3
 52     char* str = (char*)env->GetStringUTFChars(jstr, NULL);    // native str trans from java string
 53     printf("jni version : 0x%x, echo : %s, length : %d, utf8 length : %d\n", version, str, jstrLeng, jstrLengUTF8);
 54     env->ReleaseStringUTFChars(jstr, str);                           // must release utf string
 55     return jstr;
 56 }
 57 
 58 JNIEXPORT void JNICALL Java_HelloJNI_callbackEntry(JNIEnv *env, jobject thisObj, jstring jstr) {
 59     // get java class name
 60     jclass cls = env->GetObjectClass(thisObj);
 61     // use class method by class name, method name, signature
 62     // TODO : Obtaining a method ID is a relatively expensive operation.
 63     // TODO : Because you obtain the method ID separately from the method invocation, you need only perform this operation once.
 64     // TODO : Thus, it is possible to first obtain the method ID one time and then use the method ID many times at later points to invoke the same method.
 65     jmethodID jmethodId = env->GetMethodID(
 66             cls,
 67             u8"CallbackByNative",
 68             u8"(Ljava/lang/String;I)Ljava/lang/String;"
 69     );
 70     if (jmethodId == NULL) {
 71         return;
 72         // method not found
 73     }
 74     // call java method by object, method, params
 75     jstring javaResult = (jstring)env->CallObjectMethod(
 76             thisObj,
 77             jmethodId,
 78             jstr,
 79             env->GetStringLength(jstr)
 80     );
 81     char* str = (char*)env->GetStringUTFChars(javaResult, NULL);    // native str trans from java string
 82     printf("callback java result, trans to UTF8 str: %s\n", str);
 83     env->ReleaseStringUTFChars(javaResult, str);                           // must release utf string
 84 }
 85 
 86 JNIEXPORT void JNICALL Java_HelloJNI_getJavaFiled(JNIEnv *env, jobject thisObj) {
 87     jclass cls = env->GetObjectClass(thisObj);
 88     // access static int
 89     jfieldID jfieldId = env->GetStaticFieldID(cls, "integer", "I");
 90     if (jfieldId == NULL) {
 91         return;
 92     }
 93     jint jint1 = env->GetStaticIntField(cls, jfieldId);
 94     printf("java class integer is assigned to %d\n", jint1);
 95     // access member string
 96     jfieldId = env->GetFieldID(cls, "string", "Ljava/lang/String;");
 97     if (jfieldId == NULL) {
 98         return;
 99     }
100     jstring jstring1 = (jstring)env->GetObjectField(thisObj, jfieldId);
101     char* str = (char*)env->GetStringUTFChars(jstring1, NULL);    // native str trans from java string
102     printf("java object string is assigned to %s\n", str);
103     env->ReleaseStringUTFChars(jstring1, str);                           // must release utf string
104 }
105 
106 JNIEXPORT void JNICALL Java_HelloJNI_catchThrow(JNIEnv *env, jobject thisObj) {
107     jclass cls = env->GetObjectClass(thisObj);
108     // use class method by class name, method name, signature
109     jmethodID jmethodId = env->GetMethodID(cls, u8"catchThrowByJava", u8"()V");
110     if (jmethodId == NULL) {
111         return;
112         // method not found
113     }
114     env->CallVoidMethod(thisObj, jmethodId);
115     jthrowable exception = env->ExceptionOccurred();
116     if (exception != NULL) {
117         printf("detect java method exception, print call stack : \n");
118         env->ExceptionDescribe();       // Prints an exception and a backtrace of the stack to a system error-reporting channel, such as stderr. This is a convenience routine provided for debugging.
119         env->ExceptionClear();          // clear exception
120     }
121     // throw exception from native
122     jclass nativeException = env->FindClass("java/lang/IllegalArgumentException");
123     if (nativeException == 0) { /* Unable to find the new exception class, give up. */
124         return;
125     }
126     env->ThrowNew(nativeException, "thrown exception from native");   // throw new java exception
127 }
128 
129 // TODO : This program is illegal because the local reference returned from GetObjectClass is valid only until the native method returns.
130 // TODO : When the Java application calls the native method Java_FieldAccess_accessFields a second time, the native method tries to use an invalid local reference.
131 // TODO : This leads to either the wrong results or to a VM crash.
132 jstring l_jstring = NULL;
133 JNIEXPORT void JNICALL Java_HelloJNI_localReference(JNIEnv *env, jobject thisObj) {
134     if (l_jstring == NULL) {
135         l_jstring = (jstring)env->GetObjectField(thisObj,
136                                                 env->GetFieldID(
137                                                         env->GetObjectClass(thisObj),
138                                                         "string",
139                                                         "Ljava/lang/String;"
140                                                 )
141         );
142     }
143     char* str = (char*)env->GetStringUTFChars(l_jstring, NULL);    // native str trans from java string
144     printf("java object string is assigned to %s\n", str);
145     env->ReleaseStringUTFChars(l_jstring, str);                           // must release utf string
146 }
147 
148 JNIEXPORT void JNICALL Java_HelloJNI_localReferenceRelease(JNIEnv *env, jobject thisObj) {
149     if (l_jstring != NULL) {
150         env->DeleteLocalRef(l_jstring);
151         l_jstring = NULL;
152     }
153 }
154 
155 jstring g_jstring = NULL;
156 JNIEXPORT void JNICALL Java_HelloJNI_globalReference(JNIEnv *env, jobject thisObj) {
157     if (g_jstring == NULL) {
158         jstring jstring1 = (jstring)env->GetObjectField(
159                 thisObj,
160                 env->GetFieldID(
161                         env->GetObjectClass(thisObj),
162                         "string",
163                         "Ljava/lang/String;"
164                 )
165         );
166         g_jstring = (jstring)env->NewGlobalRef(jstring1);
167         // test IsSameObject
168         jstring test = (jstring)env->NewGlobalRef(jstring1);
169         if (env->IsSameObject(test, g_jstring) == JNI_TRUE) {
170             int a = 0;
171         }
172     }
173     char* str = (char*)env->GetStringUTFChars(g_jstring, NULL);    // native str trans from java string
174     printf("java object string is assigned to %s\n", str);
175     env->ReleaseStringUTFChars(g_jstring, str);                           // must release utf string
176 }
177 
178 JNIEXPORT void JNICALL Java_HelloJNI_globalReferenceRelease(JNIEnv *env, jobject thisObj) {
179     if (g_jstring != NULL) {
180         env->DeleteGlobalRef(g_jstring);
181         g_jstring = NULL;
182     }
183 }
184 
185 jweak g_weak = NULL;
186 void Java_HelloJNI_weakGlobalReference(JNIEnv *env, jobject thisObj) {
187     if (env->IsSameObject(g_weak, NULL) == JNI_FALSE) {
188         printf(" weak reference point is valid, underlying object is still valid\n");
189         char* str = (char*)env->GetStringUTFChars((jstring)g_weak, NULL);    // native str trans from java string
190         printf("java object string is assigned to %s\n", str);
191         env->ReleaseStringUTFChars((jstring)g_weak, str);                           // must release utf string
192     } else {
193         printf(" weak reference point to NULL, create new one \n");
194         if (g_jstring == NULL) {
195             jstring jstring1 = (jstring)env->GetObjectField(thisObj,
196                                                             env->GetFieldID(
197                                                                     env->GetObjectClass(thisObj),
198                                                                     "string",
199                                                                     "Ljava/lang/String;"
200                                                             )
201             );
202             g_jstring = (jstring)env->NewGlobalRef(jstring1);
203             g_weak = env->NewWeakGlobalRef(g_jstring);
204             if (env->IsSameObject(g_jstring, g_weak)) {
205                 int a = 0;
206             }
207         }
208     }
209 }
210 
211 void Java_HelloJNI_weakGlobalReferenceRelease(JNIEnv *env, jobject thisObj) {
212     if (g_weak != NULL) {
213         env->DeleteWeakGlobalRef(g_weak);
214         g_weak = NULL;
215     }
216 }
217 
218 void Java_HelloJNI_arraySum(JNIEnv * env, jobject thisObj, jintArray intArray) {
219     int  sum = 0;
220     jsize len = env->GetArrayLength(intArray);
221     // begin to end
222     jint *arrayBody = env->GetIntArrayElements(intArray, 0);
223     for (int i = 0; i < len; ++i) {
224         sum += arrayBody[i];
225     }
226     printf("jintarrry sum result: %d\n", sum);
227     env->ReleaseIntArrayElements(intArray, arrayBody, 0);
228     // array region,for big array
229     int* arrayRegion = new int[3];
230     env->GetIntArrayRegion(intArray, 1, 3, arrayRegion);
231     sum = 0;
232     if (arrayRegion != NULL) {
233         for (int i = 0; i < 3; ++i) {
234             sum += arrayRegion[i];
235         }
236         printf("jintarrry[1,3] sum result: %d\n", sum);
237     }
238     std::flush(std::cout);
239     delete [] arrayRegion;
240 }

7.1 javac生成HelloJNI.class

 javac HelloJNI.java

7.2 javah生成HelloJNI.h头文件

 javah HelloJNI

7.3 实现c++代码,编译so

或者使用g++生成so

g++ --shared HelloJNI.cpp -o libHelloJNI.so -I/usr/lib/jvm/java-8-openjdk-amd64/include -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux

7.4 java执行HelloJNI

 java HelloJNI

7.5 查找进程id

7.6 attach debug

 

posted on 2021-03-16 13:22  炽离  阅读(630)  评论(0编辑  收藏  举报

导航