深入理解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技术 的相关文章

  • Spring Boot深入理解+核心特性讲解(超强源码版)需要一定的基础观看噢

    文章目录 开篇spring boot的诞生spring boot核心特性web服务器 WebServer 64 ConditionalOnXXX工厂加载机制配置加载机制spring boot Actuator 开篇 这篇博文主要总结我自己学
  • 深入理解AlexNet网络

    AlexNet 论文 xff1a ImageNet Classification with Deep Convolutional Neural Networks 第一个典型的CNN是LeNet5网络结构 xff0c 但是第一个引起大家注意的
  • 深入理解C/C++数组和指针

    版权所有 xff0c 转载请注明出处 xff0c 谢谢 xff01 http blog csdn net walkinginthewind article details 7044380 C语言中数组和指针是一种很特别的关系 xff0c 首
  • 深入理解Redis的scan命令

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

    文章目录 service的概念kube proxy的作用kube proxy的三种模式Userspace Proxy ModeIptables Proxy ModeIPVS proxy mode service的概念 在k8s集群中 xff
  • jni 中的 extern "C" 分析

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 先看一段jni自动生成的源代码 code DO NOT EDIT THIS FILE it is machine generated include lt jni h gt
  • jni中使用extern "C"的原因

    首先 cplusplus这个宏是微软自定义宏 xff0c 大小是个整数 xff1a cplusplus This macro is defined when the C 43 43 compiler is in use You can us
  • Eclipse环境下通过Cygwin使用NDK编译jni程序

    一 认识Cygwin NDK和jni 首先来认识一下什么是Cygwin NDK和jni Cygwin Cygwin是一个在windows平台上运行的unix模拟环境 它对于学习unix linux操作环境 或者从unix到windows的应
  • Cygwin编译JNI的环境配置

    一 什么是NDK NDK提供了一系列的工具 帮助开发者快速开发C 或C 的动态库 并能自动将so和java应用一起打包成apk 这些工具对开发者的帮助是巨大的 NDK 集成了交叉编译器 并提供了相应的mk文件隔离CPU 平台 ABI 等差异
  • 让 Flutter 在鸿蒙系统上跑起来

    鸿蒙系统 HarmonyOS 是华为推出的一款分布式操作系统 那么如何在保证开发迭代效率的前提下 以相对低的成本将移动应用快速移植到鸿蒙平台上呢 美团外卖 MTFlutter 团队近期做了一次技术探索 成功地实现了 Flutter 对于鸿蒙
  • C语言基础入门详解三

    前些天发现了一个蛮有意思的人工智能学习网站 8个字形容一下 通俗易懂 风趣幽默 感觉非常有意思 忍不住分享一下给大家 点击跳转到教程 一 C语言之函数指针 include
  • 关于Java调用dll的方法

    Java语言本身具有跨平台性 如果通过Java调用DLL的技术方便易用 使用Java开发前台界面可以更快速 也能带来跨平台性 Java调用C C 写好的DLL库时 由于基本数据类型不同 使用字节序列可能有差异 所以在参数传递过程中容易出现问
  • Android JNI打印logcat日志

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

    作者 左少华 博客 http blog csdn net shaohuazuo article details 43149193 转载请注明出处 http blog csdn net shaohuazuo 1 Android线程介绍 1 线
  • Android JNI(一):JNI基础概念

    本文讲述 NDK和JNI是什么 JNI的原理 JNI开发流程的步骤 认识JNI相关的代码语法 名称概念 什么是NDK NDK 其中NDK的全拼是 Native Develop Kit Android NDK 就是一套工具集合 允许你使用C
  • java.lang.UnsatisfiedLinkError: No implementation found for

    E AndroidRuntime FATAL EXCEPTION main Process com example pimr PID 20314 java lang UnsatisfiedLinkError No implementatio
  • Java调用Native方法

    Java调用Native方法 Java中支持调用其他语言 C C 想要实现调用 需要进行以下几步操作 编写Java类并声明Native方法 package my mynative background public class Studen
  • cocos2d-x中有一个JniHelper类详细使用

    主体思路 通过JNI获取java虚拟机 再获取当前程序的JNI环境 通过JNI环境获取需要调用的java类信息 再获取需要调用的java类中的函数信息 再通过JNI环境调用 使用类信息 函数信息 调用对应的java函数 看起来好像有点复杂
  • android studio中的CMakeLists.txt,就是如此简单

    android studio中的CMakeLists txt 就是如此简单 user Linvest 目录 1 cmake minimum required VERSION 3 4 1 2 add library native lib SH
  • 使用Visual Studio 2019和IntelliJ IDEA 2018实现JAVA调用本地代码

    使用Visual Studio 2019和IntelliJ IDEA 2018实现JAVA调用本地代码 1 我们使用的工具是 IntelliJ IDEA 2018 编写java代码 和VisualStudio 2019 编写Native方法

随机推荐

  • 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一般