如何在Android下使用JNI

如何在Android下使用JNI,第1张

NDK:AndroidNDK是在SDK前面又加上了“原生”二字,即NativeDevelopmentKit,因此又被Google称为“NDK”。

NDK全称:NativeDevelopmentKit。

NDK是一系列工具的集合。

NDK提供了一系列的工具,帮助开发者快速开发C(或C)的动态库,并能自动将so和java应用一起打包成apk。这些工具对开发者的帮助是巨大的。

NDK集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。

NDK可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。

其实:

NDK就是能够方便快捷开发so文件的工具。JNI的过程比较复杂,生成so需要大量 *** 作,而NDK就是简化了这个过程。

AndroidSDK:

SDK(softwaredevelopmentkit)软件开发工具包。被软件开发工程师用于为特定的软件包、软件框架、硬件平台、 *** 作系统等建立应用软件的开发工具的集合。因此!AndroidSDk指的既是Android专属的软件开发工具包

JNI:

JavaNativeInterface(JNI)标准是java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI是本地编程接口,它使得在Java虚拟机(VM)内部运行的Java代码能够与用其它编程语言(如C、C和汇编语言)编写的应用程序和库进行交互 *** 作

当然一般需要进行如下 *** 作流程:

1)编写java程序:这里以HelloWorld为例。为了实现在java代码中调用c函数printf。

代码1:

classHelloWorld{

publicnativevoid();

static{

SystemloadLibrary("hello");

}

publicstaticvoidmain(String[]args){

newHelloWorld()();

}

}

声明native方法:如果你想将一个方法做为一个本地方法的话,那么你就必须声明改方法为native的,并且不能实现。

Load动态库:SystemloadLibrary("hello");

这里一般是以static块进行加载的。同时需要注意的是SystemloadLibrary()的参数“hello”是动态库的名字。

2)编译

javacHelloWorldjava

3)生成扩展名为h的头文件javah

JNIEXPORTvoidJNICALLJava_HelloWorld_(JNIEnv,jobject);

这个h文件相当于我们在java里面的接口,这里声明了一个Java_HelloWorld_(JNIEnv,jobject)方法,然后在我们的本地方法里面实现这个方法,也就是说我们在编写C/C程序的时候所使用的方法名必须和这里的一致)。

4)编写本地方法实现和由javah命令生成的头文件里面声明的方法名相同的方法

代码2:

#include"jnih"

#include"HelloWorldh"

#includeotherheaders

JNIEXPORTvoidJNICALLJava_HelloWorld_(JNIEnvenv,jobjectobj)

{

printf("Helloworld!/n");

return;

}

注意代码2中的第1行,需要将jnih(该文件可以在%JAVA_HOME%/include文件夹下面找到)文件引入,因为在程序中的JNIEnv、jobject等类型都是在该头文件中定义的;另外在第2行需要将HelloWorldh头文件引入。然后保存为c就ok了。

5)生成动态库

这里以在Windows中为例,需要生成dll文件。在保存c文件夹下面,使用VC的编译器cl成。cl-I%java_home%/include-I%java_home%/include/win32-LDc-Fehellodll注意:生成的dll文件名在选项-Fe后面配置,这里是hello,因为在HelloWorldjava文件中我们loadLibary的时候使用的名字是hello。

另外需要将-I%java_home%/include-I%java_home%/include/win32参数加上,因为在第四步里面编写本地方法的时候引入了jnih文件。

JDK动态代理是基于接口使用,通过ProxynewProxyInstance方法使用。

传入参数:当前类加载器、目标接口、带目标类的InvocationHandle实现类

1、Proxy#newProxyInstance

2、Constructor#newInstance

4、sunreflectNativeConstructorAccessorImpl#newInstance

4、sunreflectNativeConstructorAccessorImpl#newInstance

ReflectionFactoryinflationThreshold 默认值是15

5、native的newInstance0

3、sunreflectDelegatingConstructorAccessorImpl#newInstance

4、执行GeneratedConstructorAccessor3代理类方法

第16次调用generate方法生成代理类GeneratesConstructorAccessor,第17次执行GeneratesConstructorAccessor代理类方法

反射类加载器会导致Perm溢出

ConstructorAccessor 有下面实现类

1、NativeConstructorAccessorImpl

JNI(java本地接口)

2、DelegatingConstructorAccessorImpl

注入ConstructorAccessorImpl属性(值是1或3),实现newInstance

3、GeneratedConstructorAccessorX

通过代理类

MethodAccessor 有下面实现类

1、NativeMethodAccessorImpl

NativeMethodAccessorImpl是通过JNI(java本地接口)存取器获取反射类字节码信息

2、DelegatingMethodAccessorImpl

DelegatingMethodAccessorImpl注入MethodAccessorImpl属性(值是1或3),实现invoke调用

3、GeneratedMethodAccessorX

通过代理类加载反射类字节码

NativeConstructorAccessorImpl或NativeMethodAccessorImpl都有一个字段numInvocations。用来计算调用JNI次数

当大于15就会生成GeneratedConstructorAccessorX或GeneratedConstructorAccessorX的字节码类文件,该字节码通过DelegatingClassLoader类加载。

为什么设计这种机制:为了提高效率

MethodAccessorGenerator类

generate方法实现了

1、asm生成字节码数组

2、defineClass生成DelegatingClassLoader代理类加载器

3、generateName方法生成字节码文件GeneratedXXXAccessorX

Inflation机制提高了反射的性能,但是对于重度使用有两个问题

1、初次加载性能较低

2、动态加载的字节码导致PermGen持续增长

JDK是基于接口实现

Inflation机制

关键是生成代理类和调用inovke方法的实现方式

1、JNI

2、asm字节码

以上就是关于如何在Android下使用JNI全部的内容,包括:如何在Android下使用JNI、如何用JNI技术提高Java的性能详解、AndroidNDK开发简介NDK和SDK以及JNI有什么关系_安卓ndk是干嘛的等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/9635676.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-30
下一篇 2023-04-30

发表评论

登录后才能评论

评论列表(0条)

保存