• 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
    ", 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
    ");
     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
    ");
     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
    ", 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
    ", 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
    ", 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
    ", 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 : 
    ");
    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
    ", 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
    ", 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
    ");
    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
    ", str);
    191         env->ReleaseStringUTFChars((jstring)g_weak, str);                           // must release utf string
    192     } else {
    193         printf(" weak reference point to NULL, create new one 
    ");
    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
    ", 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
    ", 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

  • 相关阅读:
    Netty学习笔记四:NIO实现群聊
    Netty学习三:NIO
    Netty学习二:IO模型 BIO
    Netty学习一:netty是什么
    idea远程debug
    filter,interceptor,controllerAdvice,aspect,controller执行顺序
    springboot使用多个@RestControllerAdvice时的拦截顺序
    记一次RestControllerAdvice无法拦截Filter内抛出异常
    SpringBoot声明式事务的简单运用
    mybatis plus 和PageHelper依赖冲突
  • 原文地址:https://www.cnblogs.com/hgwang/p/14542967.html
Copyright © 2020-2023  润新知