在博客java JNI (一)虚拟机中classloader的JNILibrary 中讨论了java中的Library 是由classloader 来load的,那我们来看看 classloader是如何去load 一个library的。

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的更多相关文章

  1. DHCP原理与LINUX下的配置

    DHCP原理与LINUX下的配置 目录 DHCP原理与LINUX下的配置 一.DHCP工作原理 1.DHCP概述 2.DHCP的优势 3.DHCP的分配方式 (1)自动分配 (2)手动分配 (3)动态 ...

  2. 一次失败的尝试hdfs的java客户端编写(在linux下使用eclipse)

    一次失败的尝试hdfs的java客户端编写(在linux下使用eclipse) 给centOS安装图形界面 GNOME桌面环境 https://blog.csdn.net/wh211212/artic ...

  3. MongoDB和Java(1):Linux下的MongoDB安装

    最近花了一些时间学习了下MongoDB数据库,感觉还是比较全面系统的,涉及了软件安装.客户端操作.安全认证.副本集和分布式集群搭建,以及使用Spring Data连接MongoDB进行数据操作,收获很 ...

  4. Linux下安装load generator步骤及问题解决

    Linux下安装load generator步骤及问题解决 上一篇 / 下一篇  2014-08-06 18:33:00 / 个人分类:loadrunner相关 查看( 146 ) / 评论( 0 ) ...

  5. Redis(二)linux下redis安装

    上篇讲解了redis在windows下的安装,接下来看看在linux下如何安装redis(纯菜鸟入门级别)? (1)redis的下载及编译 这里,首先进入存放文件目录(我的云服务器的是:cd /jel ...

  6. LINUX下CPU Load Average的一点研究

    背景: 公司的某个系统工作在基于Linux的Cent OS下,一个host下同时连接了许多client, 最近某台Host总是显示CPU Load Average过高,我们单纯的以为是CPU的占用过高 ...

  7. 实验二 Linux下C语言编程基础

    1. 熟悉Linux系统下的开发环境 2. 熟悉vi的基本操作 3. 熟悉gcc编译器的基本原理 4. 熟练使用gcc编译器的常用选项 5 .熟练使用gdb调试技术 6. 熟悉makefile基本原理 ...

  8. Nginx学习系列二Linux下Nginx实现负载均衡

    关于在本地虚拟机(VMware 14)下安装Linux同时安装Nginx,请参考Nginx学习系列之搭建环境 1.启动Nginx 在Nginx安装成功的前提下,启动Nginx 已root模式登陆(权限 ...

  9. [笔记]MongoDB 二(Linux下MongoDB API C++编程)

    一.连接类 DBClientConnection,派生自DBClientBase.DBClientBase类是实现query, update, insert, remove等功能. 构造函数:DBCl ...

随机推荐

  1. gitlab-ce 安装、汉化与阿里邮箱配置(注意是CE)

    环境准备 yum install curl openssh-server openssh-clients postfix cronie policycoreutils-python –y curl h ...

  2. docker的理解

    作者:刘允鹏链接:https://www.zhihu.com/question/28300645/answer/67707287来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...

  3. Websocket实现群聊、单聊

    Websocket 使用的第三方模块:gevent-websocket 群聊 ws群聊.py中的内容 from flask import Flask, request, render_template ...

  4. [剑指Offer]52-两个链表的第一个公共节点

    题目链接 https://www.nowcoder.com/practice/6ab1d9a29e88450685099d45c9e31e46?tpId=13&tqId=11189&t ...

  5. Delphi: Class Static Methods

    在Delphi中,自Delphi 2007之后,支持static形式的class方法,样式比如: type TMyClass = class strict private class var FX: ...

  6. 《基于Nginx的中间件架构》学习笔记---1.环境配置

    一.环境调试确认 (四项确认) 1.确认系统网络 ping www.baidu.com 2.确认yum可用 yum list|grep gcc 3.确认关闭iptables规则 iptables -L ...

  7. swift 关于didSet 和willSet赋值的注意点

    1. 初始化赋值的时候都不会走这个的方法, 需要在创建结构体后或对象后,在赋值,此时才会走这个方法

  8. linux修改hosts

    vim /etc/hosts

  9. (转载)Ubuntu下安装Qt

    转载自:http://blog.csdn.net/timidsmile/article/details/7716201 Ubuntu下安装Qt 1: sudo apt-get install qt4- ...

  10. better-scroll使用总结

    参考:https://zhuanlan.zhihu.com/p/27407024 better-scroll使用小结 核心就是这4个 <script> import BScroll fro ...