深入理解JNI技术

2023-05-16

一、JNI是什么?

JNI是Java Native Interface的缩写,译为Java本地调用。JNI是一种技术。

二、JNI技术的用途?

  • Java程序中的函数调用Native程序中的函数。Native一般指使用C/C++编写的函数。

  • Native程序中的函数调用Java程序中的函数。

三、注册JNI函数

  • 静态注册

  Java层函数通过Java编译成.class文件,再通过Javah工具将将.class生成为JNI层的*.h头文件,在*.h头文件里有对应Java层的函数,在JNI层实现相关函数即可。

javah -o test packagename.classname

  • 动态注册

  Java Native函数与JNI函数是一一对应的关系,所以,有一个数据结构存储着对应关系,这个数据结构就是JNINativeMethod结构体。

typedef struct {

constchar* name;

constchar* signature;

void* fnPtr;

} JNINativeMethod;

JNINativeMethod name:Java函数名称,不包括包路径。

JNINativeMethod signature:Java函数签名,用字符串存储,签名信息由参数类型+返回值类型组成。

JNINativeMethod fnPtr:JNI层对应的函数指针,注意fnPtr是Viod*。

  在运行时,AndroidRuntime类提供方法registerNativeMethod函数完成java函数的注册。registerNativeMethod函数通过调用jniRegisterNativeMethods函数实现函数注册。jniRegisterNativeMethods函数是Android平台提供的帮助函数。

  那么,在什么时候完成注册或者函数调用呢?

  在Java层通过System.loadLibrary函数加载JNI动态库,在System.loadLibrary函数调用完成后,会调用JNI_OnLoad函数,如果有就调用它,函数注册或者相关初始化在JNI_OnLoad函数中完成。

/**

* Loads the native library specified by the <code>libname</code>

* argument. The <code>libname</code> argument must not contain any platform

* specific prefix, file extension or path. If a native library

* called <code>libname</code> is statically linked with the VM, then the

* JNI_OnLoad_<code>libname</code> function exported by the library is invoked.

* See the JNI Specification for more details.

*

* Otherwise, the libname argument is loaded from a system library

* location and mapped to a native library image in an implementation-

* dependent manner.

* <p>

* The call <code>System.loadLibrary(name)</code> is effectively

* equivalent to the call

* <blockquote><pre>

* Runtime.getRuntime().loadLibrary(name)

* </pre></blockquote>

*

* @param libname the name of the library.

* @exception SecurityException if a security manager exists and its

* <code>checkLink</code> method doesn't allow

* loading of the specified dynamic library

* @exception UnsatisfiedLinkError if either the libname argument

* contains a file path, the native library is not statically

* linked with the VM, or the library cannot be mapped to a

* native library image by the host system.

* @exception NullPointerException if <code>libname</code> is

* <code>null</code>

* @see java.lang.Runtime#loadLibrary(java.lang.String)

* @see java.lang.SecurityManager#checkLink(java.lang.String)

*/

@CallerSensitive

publicstaticvoid loadLibrary(String libname) {

Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname);

}

  JNI_OnLoad是JNI层方法

jint JNI_OnLoad(JavaVM* vm, void* reserved __unused)

{

// 函数注册

}

四、数据类型转换

  Java层数据类型在JNI层有一一对应的数据类型。  

五、垃圾回收

  在Java中,创建对象使用完后,通过Java GC回收对象和释放内存。那么,Java GC对JNI层有什么影响?Java层变量传入JNI层后如何使用?

  如下代码通过Android源码修改:

// Adnroid源码 frameworks/base/core/jni/android_media_MediaRecorder.cpp

JNIMediaRecorderListener::JNIMediaRecorderListener(JNIEnv* env, jobject thiz, jobject weak_thiz)

{

// Hold onto the MediaRecorder class for use in calling the static method

// that posts events to the application thread.

jclass clazz = env->GetObjectClass(thiz);

if (clazz == NULL) {

ALOGE("Can't find android/media/MediaRecorder");

jniThrowException(env, "java/lang/Exception", NULL);

return;

}

mClass = (jclass)env->NewGlobalRef(clazz);

// We use a weak reference so the MediaRecorder object can be garbage collected.

// The reference is only used as a proxy for callbacks.

mObject = weak_thiz;

}

  上面代码正常情况是没问题的,如果此广告在Java层调用将传递参数到JNI层,通过mOjbect = week_thiz赋值,当前Java层GC回收了week_thiz变量。那么,在其它地方使用mObject变量就会出现异常,mObject指向一个野指针。

  那么,有一个疑问,正常在Java层mOjbect = week_thiz这个赋值,引用计数加1,不应该会被GC回收的。但是,需要注意在JNI层mOjbect = week_thiz这样的语句,是不会增加引用计数的。

  正确写法,未修改Android源码,上面的源码是人为改错的:

JNIMediaRecorderListener::JNIMediaRecorderListener(JNIEnv* env, jobject thiz, jobject weak_thiz)

{

// Hold onto the MediaRecorder class for use in calling the static method

// that posts events to the application thread.

jclass clazz = env->GetObjectClass(thiz);

if (clazz == NULL) {

ALOGE("Can't find android/media/MediaRecorder");

jniThrowException(env, "java/lang/Exception", NULL);

return;

}

mClass = (jclass)env->NewGlobalRef(clazz);

// We use a weak reference so the MediaRecorder object can be garbage collected.

// The reference is only used as a proxy for callbacks.

mObject = env->NewGlobalRef(weak_thiz);

}

  在JNI层引用分为Local Reference(本地引用)和Global Reference(全局引用),还有一种特殊的引用 Weak Global Reference(弱全局引用)。

  Local Reference:本地引用,在JNI层函数中使用的非全局引用都是Local Reference,包括函数调用传递的参数和JNI层本地创建的jobject。Local Reference在JNI最大的好处就是,在JNI层函数返回后,这些jobject就可能被GC回收。

  Global Reference:全局引用,全局引用的对象不主动释放,那么,将永远不会被GC回收。

  Weak Global Reference:弱全局引用,一种特殊的全局引用,在程序运行过程中可能被GC回收。  

六、异常处理

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

深入理解JNI技术 的相关文章

  • 通过示例去看JNI中为什么使用extern “C“

    经验总结 在JNI开发过程中 xff0c 我们使用C 43 43 去写一个动态库 xff0c 由于C 43 43 编译器对于函数的符号的生成需要进行名字修饰处理 xff0c 然后生成的函数符号不再跟源代码中定义的函数名一致 这样导致调用方通
  • 深入理解Tomcat虚拟目录

    我们知道 xff0c Web网站中的内容 xff08 包括网页 xff0c 图片 xff0c 音频文件等 xff09 一般都存放在App的目录下 但随着网站内容的不断丰富 xff0c 用户需要把不同层次的内容组织成网站的子目录 我们通常的做
  • eclipse报错:Failed to load the JNI shared library

    电脑自装系统以来 xff0c 好久没有写java代码了 xff0c 所以一直也没用 eclipse IDE xff0c 今天将eclipse打开 xff0c 报了个问题 xff0c Failed to load the JNI shared
  • jni开发-GetMethodID与CallObjectMethod的坑

    在java层中声明一个方法用于创建一个audiotrack xff0c 在C层中调用这个方法并获取audiotrack对象 先看下面的代码 xff1a SuPlayer java public AudioTrack createAudioT
  • 深入理解C/C++数组和指针

    版权所有 xff0c 转载请注明出处 xff0c 谢谢 xff01 http blog csdn net walkinginthewind article details 7044380 C语言中数组和指针是一种很特别的关系 xff0c 首
  • 《Windows核心编程》第3章——深入理解handle

    本文借助windbg来理解程序中的函数如何使用handle对句柄表进行查询的 所以先要开启Win7下Windbg的内和调试功能 解决win7下内核调试的问题 win7下debug默认无法进行内核调试 xff08 xff01 process等
  • 深入理解Redis的scan命令

    熟悉Redis的人都知道 xff0c 它是单线程的 因此在使用一些时间复杂度为O N 的命令时要非常谨慎 可能一不小心就会阻塞进程 xff0c 导致Redis出现卡顿 有时 xff0c 我们需要针对符合条件的一部分命令进行操作 xff0c
  • 深入理解Java枚举类型(enum)

    版权申明 未经博主同意 xff0c 谢绝转载 xff01 xff08 请尊重原创 xff0c 博主保留追究权 xff09 http blog csdn net javazejian article details 71333103 出自 z
  • jni 中的 extern "C" 分析

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 先看一段jni自动生成的源代码 code DO NOT EDIT THIS FILE it is machine generated include lt jni h gt
  • 深入理解Kotlin无参构造函数

    Unsafe 创建实例 在java中 创建一个对象 其实主要就是3种方法 通过new 关键字来创建 这种是最常见的 通过反射构造方法来创建对象 这种也不少见 很多框架中都有使用 Unsafe类来创建实例 xff0c 这种情况非常少见 这里先
  • Android Studio JNI开发入门教程

    概述 在Andorid Studio不支持JNI开发之前大家一般都是使用Eclipse开发JNI 各种配置让人觉得很蛋疼 从Andorid Studio支持JNI开发后 让我们开发JNI变的如此简单 下面我就介绍一下Android Stud
  • Android调用OpenCV配置方法

    文章目录 1 环境 2 准备工作 3 开始构建示例项目 4 集成opencv库 4 1 导入opencv库 4 2 配置CMakeLists txt 4 3 代码声明及实现 4 3 运行效果 5 可能遇到的其他错误及解决方法 5 1 包冲突
  • 关于Java调用dll的方法

    Java语言本身具有跨平台性 如果通过Java调用DLL的技术方便易用 使用Java开发前台界面可以更快速 也能带来跨平台性 Java调用C C 写好的DLL库时 由于基本数据类型不同 使用字节序列可能有差异 所以在参数传递过程中容易出现问
  • NDK 入门HelloJni 以及 javah 找不到类文件的问题 解决(ubuntu)

    1 首先创建一个android工程 创建一个HelloJni java 文件 并编写如下代码 package com ndk import android app Activity import android os Bundle impo
  • JNI中的回调函数,C++中的vector数组和Java中int数组的转换

    简介 使用JNI的过程中 在Java端使用C 程序中的回调函数 对程序来说很方便 最近在做图形识别的过程中遇到了数组的转换方面的问题 后来仔细想了一下 在网上简单看了点资料 发现在JNI层对vector数组转换 最后在回调中返回到Java端
  • 在C/C++中调用Java代码

    JNI就是Java Native Interface 即可以实现Java调用本地库 也可以实现C C 调用Java代码 从而实现了两种语言的互通 可以让我们更加灵活的使用 通过使用JNI可以从一个侧面了解Java内部的一些实现 本文使用的环
  • Android JNI打印logcat日志

    在 JNI 中打印日志可以使用 android log print 函数来实现 该函数是 Android NDK 提供的一个用于在本地代码中输出日志消息到 logcat 的方法 要在 JNI 中打印日志 请按照以下步骤进行操作 在你的 JN
  • jni入门级别教程

    前提条件 笔者假想着 能看到这篇博客的读者 NDK环境 已经配置好了哈 开发步骤 第一步 新建工程 工程建完之后在真机或模拟器上运行一遍 确保工程建的没问题 第二步 配置NDK 第三步 在Java中添加 native 函数 并 调用 我们这
  • android studio中的CMakeLists.txt,就是如此简单

    android studio中的CMakeLists txt 就是如此简单 user Linvest 目录 1 cmake minimum required VERSION 3 4 1 2 add library native lib SH
  • 导致java.lang.UnsatisfiedLinkError错误的一种解决办法

    欢迎转载请注明出处http blog csdn net ning gg article details 53641254 在程序中加入so文件导致java lang UnsatisfiedLinkError错误的一种解决办法 可能这个解决办

随机推荐

  • Vmware vSphere(一)安装vSphere client 以及 ubuntu

    大致流程见附件 VMware Tools 安装 xff0c 使用 xff0c 命令 xff1a vmware toolbox http blog csdn net dzassn article details 1633577 vmware
  • syslog 协议及格式

    官方文档 xff1a http tools ietf org html rfc5424 6 Syslog Message Format 6 2 HEADER 6 2 1 PRI PRI 61 lt Facility 0 23 8 43 Se
  • chm打不开

    chm文件打开看不到右边的内容 1 操作系统为了安全对下载的chm文件进行了锁定 xff0c 只需要在打开前右键单击该chm文件选择 属性 xff0c 然后在 常规 选项卡的下方单击 解除锁定 按钮就可以了 2 如果还是不能看 xff0c
  • 形式语言与自动机笔记

  • 关于Keil开发C51单片机的头文件问题

    我用的德飞莱的资料 在学习STM32中回想起学C51单片机时 xff0c 有个问题一直没解决 xff0c 就是头文件regx52 h和reg52 h的区别 因为在引用regx52 h时 xff0c 可以直接用P1 1 P3 2这些小口 但是
  • JAXB(二)Map属性映射

    JAXB support Collection List Set does not support Map not Collection XmlAdapter lt ValueType BoundType gt use List to im
  • JAXB(三)xsd 验证

    现在只有最简单的关联映射验证 关键点 xff1a jaxbMarshaller setSchema sch 还不会验证集合类型 xff1a List Set Map 以后再把JAXB xff08 二 xff09 的例子加上 xff0c 64
  • jstat

    http blog csdn net swpihchj article details 8197204
  • Effctive Java 笔记

    8 重写equals xff0c 只适合值类 xff08 枚举类除外 xff09 自反性 xff1a x equals x 61 61 true 对称性 x equals y 61 61 true 必然 y equals x 61 61 t
  • maven

    http blog csdn net zjf280441589 article details 53044308 http www infoq com maven Porject groupId 43 artifactId 43 versi
  • Linux第二课:Ubuntu 操作入门(内含:1Ubuntu 下打开终端+2 Linux 文件属性+3 设置屏幕+4 系统关机与重启+5.文件浏览器)

    Ubuntu 操作入门 2 2 1Ubuntu 下打开终端 方法1 点击 Ubuntu 桌面左上角图标进入搜索框 xff0c 输入 term 可以弹出终端 Terminal 程序 方法2 xff1a 桌面或者在文件浏览器的任何目录下右键鼠标
  • 堆中存什么?栈中存什么?

    堆中存的是对象 栈中存的是基本数据类型 和堆中对象的引用 一个对象的大小是不可估计的 xff0c 或者说是可以动态变化的 xff0c 但是在栈中 xff0c 一个对象只对应了一个4btye的引用 xff08 堆栈分离的好处 xff1a xf
  • 计算一个数的N次方

    计算一个数的N次方时 xff0c 我们先设定两个参数n和k xff0c n表示你要输入的数 xff0c k表示这个数的次方 这个时候我们必须对次方数k作出分类 xff1a k 61 0 return 1 其他 xff1a return n
  • 用结构体编写电话通讯录

    用结构体数组编写电话通讯录 xff0c 必须得知道结构体的形式 xff0c 那先把结构体定义回顾一下 xff1a 一般形式为 xff1a xff08 1 xff09 struct 结构体名称 成员表列 数组名 数组长度 如 xff1a st
  • linux(centos)下安装git并上传代码些许步骤(亲自验证过的步骤)

    以前听说了好多次github xff0c 但直到最近才第一次学习使用github来托管自己在linux下的代码 xff01 说实话 xff0c 我自己在使用的时候从网上查了好多教程 xff0c 但总觉得难以掌握 xff08 步骤过于繁琐 x
  • shell具体执行过程及自主实现shell解释器

    在编写shell 解释器之前 xff0c 先来分析几个知识点 xff1a xff08 1 xff09 shell 执行命令时步骤 xff1a xff08 如下图 xff09 xff08 2 xff09 shell 执行脚本时的步骤 xff1
  • Linux下的桥接模式和Nat模式的区别

    先来看一下linux在的桥接模式和Nat模式的差别 xff1a 桥接模式 xff1a Nat模式 xff1a 真正的接触这个问题是因为同学要给我远程传输文件 xff0c 这个时候就调节至桥接模式下 xff0c 进行ping 尽管我们用的是同
  • C知识点整合

    C语言总结 一 语法 1 常见的数据内置类型所占字节 xff08 64 位下 xff09 xff1a char 1 int 4 float 4 long 4 double 8 Longlong 8 2 变量 xff1a xff08 1 xf
  • 判断一棵二叉树是否为完全二叉树

    1 完全二叉树的特点 xff08 来自专业定义 xff09 看到上面完全二叉树的特点 xff0c 我可以将其特点按照自己的 理解归纳为以下几点 xff1a xff08 1 xff1a 若二叉树最下面一层有节点出现 xff0c 那么这个节点一
  • 深入理解JNI技术

    一 JNI是什么 xff1f JNI是Java Native Interface的缩写 xff0c 译为Java本地调用 JNI是一种技术 二 JNI技术的用途 xff1f Java程序中的函数调用Native程序中的函数 Native一般