java JNI 实现原理 (二) Linux 下如何 load JNILibrary
ClassLoader.c
[cpp]
JNIEXPORT void JNICALL
Java_java_lang_ClassLoader_00024NativeLibrary_load
(JNIEnv *env, jobject this, jstring name)
{
const char *cname;
jint jniVersion;
jthrowable cause;
void * handle; if (!initIDs(env))
return; cname = JNU_GetStringPlatformChars(env, name, );
if (cname == )
return;
handle = JVM_LoadLibrary(cname);
if (handle) {
const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS;
JNI_OnLoad_t JNI_OnLoad;
int i;
for (i = ; i < sizeof(onLoadSymbols) / sizeof(char *); i++) {
JNI_OnLoad = (JNI_OnLoad_t)
JVM_FindLibraryEntry(handle, onLoadSymbols[i]);
if (JNI_OnLoad) {
break;
}
}
if (JNI_OnLoad) {
JavaVM *jvm;
(*env)->GetJavaVM(env, &jvm);
jniVersion = (*JNI_OnLoad)(jvm, NULL);
} else {
jniVersion = 0x00010001;
} cause = (*env)->ExceptionOccurred(env);
if (cause) {
(*env)->ExceptionClear(env);
(*env)->Throw(env, cause);
JVM_UnloadLibrary(handle);
goto done;
} if (!JVM_IsSupportedJNIVersion(jniVersion)) {
char msg[];
jio_snprintf(msg, sizeof(msg),
"unsupported JNI version 0x%08X required by %s",
jniVersion, cname);
JNU_ThrowByName(env, "java/lang/UnsatisfiedLinkError", msg);
JVM_UnloadLibrary(handle);
goto done;
}
(*env)->SetIntField(env, this, jniVersionID, jniVersion);
} else {
cause = (*env)->ExceptionOccurred(env);
if (cause) {
(*env)->ExceptionClear(env);
(*env)->SetLongField(env, this, handleID, (jlong)NULL);
(*env)->Throw(env, cause);
}
goto done;
}
(*env)->SetLongField(env, this, handleID, ptr_to_jlong(handle)); done:
JNU_ReleaseStringPlatformChars(env, name, cname);
}
1. JVM_LoadLibrary
jvm中load library 核心函数,实现也非常简单,在linux下调用了系统函数dlopen去打开库文件,详细可参考方法
[cpp]
void * os::dll_load(const char *filename, char *ebuf, int ebuflen)
2. JVM_FindLibraryEntry
JVM在加载库文件时候,会去尝试查找库中的JNI_ONLOAD方法的地址,而在Linux中调用了dlsym函数通过前面的dlopen加载库的指针去获取方法的地址,而dlsym在glibc2.0是非线程安全的,需要锁的保护,虽然在java中加载库已经有锁的保护,但只是针对同一个classloader对象的细粒度锁。
[cpp]
void* os::dll_lookup(void* handle, const char* name) {
pthread_mutex_lock(&dl_mutex);
void* res = dlsym(handle, name);
pthread_mutex_unlock(&dl_mutex);
return res;
}
3. 方法JNI_OnLoad
JVM提供了一种方式允许你在加载库文件的时候做一些你想做的事情,也就是JNI_OnLoad方法
在2中提到过在加载动态链接库,JVM会去尝试查找JNI_OnLoad方法,同时也会调用该函数,这样你个人可以在函数里做一些初始化的事情,比如register native方法。
[cpp]
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{}
JNI_OnLoad中返回的是JNI 的version,在1.6版本的情况下支持如下
[cpp]
jboolean Threads::is_supported_jni_version(jint version) {
if (version == JNI_VERSION_1_2) return JNI_TRUE;
if (version == JNI_VERSION_1_4) return JNI_TRUE;
if (version == JNI_VERSION_1_6) return JNI_TRUE;
return JNI_FALSE;
}
完整的加载过程就是
首先先加载动态链接库,尝试查找JNI_OnLoad方法,并且运行方法,对我们来说从而实现可以自定义的初始化方法。
java JNI 实现原理 (二) Linux 下如何 load JNILibrary的更多相关文章
- DHCP原理与LINUX下的配置
DHCP原理与LINUX下的配置 目录 DHCP原理与LINUX下的配置 一.DHCP工作原理 1.DHCP概述 2.DHCP的优势 3.DHCP的分配方式 (1)自动分配 (2)手动分配 (3)动态 ...
- 一次失败的尝试hdfs的java客户端编写(在linux下使用eclipse)
一次失败的尝试hdfs的java客户端编写(在linux下使用eclipse) 给centOS安装图形界面 GNOME桌面环境 https://blog.csdn.net/wh211212/artic ...
- MongoDB和Java(1):Linux下的MongoDB安装
最近花了一些时间学习了下MongoDB数据库,感觉还是比较全面系统的,涉及了软件安装.客户端操作.安全认证.副本集和分布式集群搭建,以及使用Spring Data连接MongoDB进行数据操作,收获很 ...
- Linux下安装load generator步骤及问题解决
Linux下安装load generator步骤及问题解决 上一篇 / 下一篇 2014-08-06 18:33:00 / 个人分类:loadrunner相关 查看( 146 ) / 评论( 0 ) ...
- Redis(二)linux下redis安装
上篇讲解了redis在windows下的安装,接下来看看在linux下如何安装redis(纯菜鸟入门级别)? (1)redis的下载及编译 这里,首先进入存放文件目录(我的云服务器的是:cd /jel ...
- LINUX下CPU Load Average的一点研究
背景: 公司的某个系统工作在基于Linux的Cent OS下,一个host下同时连接了许多client, 最近某台Host总是显示CPU Load Average过高,我们单纯的以为是CPU的占用过高 ...
- 实验二 Linux下C语言编程基础
1. 熟悉Linux系统下的开发环境 2. 熟悉vi的基本操作 3. 熟悉gcc编译器的基本原理 4. 熟练使用gcc编译器的常用选项 5 .熟练使用gdb调试技术 6. 熟悉makefile基本原理 ...
- Nginx学习系列二Linux下Nginx实现负载均衡
关于在本地虚拟机(VMware 14)下安装Linux同时安装Nginx,请参考Nginx学习系列之搭建环境 1.启动Nginx 在Nginx安装成功的前提下,启动Nginx 已root模式登陆(权限 ...
- [笔记]MongoDB 二(Linux下MongoDB API C++编程)
一.连接类 DBClientConnection,派生自DBClientBase.DBClientBase类是实现query, update, insert, remove等功能. 构造函数:DBCl ...
随机推荐
- axaj 的回调
//为了动态生成表格获取数据用ajax获取servlet回调数据 <script> $.ajax({ url = "servlet地址", type : "p ...
- WdatePicker控件Javascript取得当前时间、取得减30分钟时间
1.取得当前时间 function getNowFormatDate() { var date = new Date(); var seperator1 = "-"; var se ...
- mac item2 ssh
一.常规ssh登录流程 ssh登陆有三个参数,主机名,用户名,用户密码,流程都是一样. 1.ssh 用户名@主机名 2.返回包含(yes/no)的字符串,此时输入 “yes" 3.然后再返回 ...
- PTA 7-50 畅通工程之局部最小花费问题(最小生成树Kruskal)
某地区经过对城镇交通状况的调查,得到现有城镇间快速道路的统计数据,并提出“畅通工程”的目标:使整个地区任何两个城镇间都可以实现快速交通(但不一定有直接的快速道路相连,只要互相间接通过快速路可达即可). ...
- xadmin系列之零碎的小点
1.获取某张表的某个字段的属性 意思就是获取括号中的属性 class app1Person(models.Model): pid = models.AutoField(primary_key=True ...
- C++ 读取文本文件内容到结构体数组中并排序
成绩排行:从Score.txt文件读取学生信息,对其进行排序,按回答题数从大到小排,若相等,按分数从小到大排 #include<iostream> #include<fstream& ...
- MongoDB的增、删、改、查操作(五)
按照我们关系型数据库的思想,一个服务器要想存放数据,首先要有数据库,表,字段,约束,当然了也少不了主键,外键,索引,关系等: 但是在MongoDB的世界里边,我们不用预先的去创建这些信息从而直接来使用 ...
- Volley框架原理
Volley有如下优点: 1. 自动调度网络请求 2. 多并发请求 (源于开了多个线程)3. 本地Cache自动缓存网络请求结果 4. 支持设置请求优先级 5. 支持取消单个请求或者取消所有请求 6. ...
- Android的事件分发机制
public boolean dispatchTouchEvent(MotionEvent event) 通过方法名我们不难猜测,它就是事件分发的重要方法.那么很明显,如果一个MotionEvent传 ...
- Ado.net简单快捷帮助类
using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; usin ...