/ JVM_LoadLibrary() /
JVM_LoadLibrary() 是 JVM 这层加载 library 的最后一个实现,具体步骤如下:
- 定义 1024 长度的 char 数组和接收加载结果的指针
- 调用 dll_load() 加载 library,其细节见下章节
- 加载失败的话,打印 library 名称和错误 message
- 同时抛出 UnsatisfiedLinkError
- 反之将加载结果返回
// vm/prims/jvm.cppJVM_ENTRY_NO_ENV(void*, JVM_LoadLibrary(const char* name))JVMWrapper2("JVM_LoadLibrary (%s)", name);char ebuf[1024];void *load_result;{ThreadToNativeFromVM ttnfvm(thread);load_result = os::dll_load(name, ebuf, sizeof ebuf);}if (load_result == NULL) {char msg[1024];jio_snprintf(msg, sizeof msg, "%s: %s", name, ebuf);Handle h_exception =Exceptions::new_exception(...);THROW_HANDLE_0(h_exception);}return load_result;JVM_END / dll_load() /
dll_load() 的实现跟平台相关,比如 bsd 平台就是调用标准库的 dlopen(),而其最终的结果来自于 do_dlopen(),其将通过 find_library() 得到 soinfo 实例,内部将执行 to_handle() 得到 library 的指针 。
// bionic/libdl/libdl.cppvoid* dlopen(const char* filename, int flag) {const void* caller_addr = __builtin_return_address(0);return __loader_dlopen(filename, flag, caller_addr);}void* __loader_dlopen(const char* filename, int flags, const void* caller_addr) {return dlopen_ext(filename, flags, nullptr, caller_addr);}static void* dlopen_ext(...) {ScopedPthreadMutexLocker locker(&g_dl_mutex);g_linker_logger.ResetState();void* result = do_dlopen(filename, flags, extinfo, caller_addr);if (result == nullptr) {__bionic_format_dlerror("dlopen failed", linker_get_error_buffer());return nullptr;}return result;}void* do_dlopen(...) {...if (si != nullptr) {void* handle = si->to_handle();si->call_constructors();failure_guard.Disable();return handle;}return nullptr;} / JNI_OnLoad() /
JNI_OnLoad() 定义在 jni.h 中,当 library 被 JVM 加载时会回调,该方法内一般会通过 registerNatives() 注册 native 方法并返回该 library 所需的 JNI 版本 。该头文件还定义了其他函数和常量,比如 JNI 1.1 等数值 。
// jni.h...struct JNIEnv_ {...jint RegisterNatives(jclass clazz, const JNINativeMethod *methods,jint nMethods) {return functions->RegisterNatives(this,clazz,methods,nMethods);}jint UnregisterNatives(jclass clazz) {return functions->UnregisterNatives(this,clazz);}}.../* Defined by native libraries. */JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved);#define JNI_VERSION_1_1 0x00010001... / 结语 /

文章插图
总体流程可以归纳如下:
- System 类提供的 load() 加载 so 的完整的路径名且带文件后缀,等同于直接调用 Runtime 类提供的 load();loadLibrary() 用于加载指定 so 的名称,等同于调用 Runtime 类提供的 loadLibrary() 。
- 两者都将通过 SecurityManager 检查 so 的访问权限以及名称是否合法
- 之后调用 ClassLoader 类的 loadLibrary() 实现,区别在于前者指定的是否是绝对路径的 isAbsolute 参数是否为 true
- ClassLoader 首先需要通过 System 提供的 getProperty() 获取 JVM 配置的存放 usr、system library 路径字符串数组
- 如果 library name 非绝对路径,需要先调用 findLibrary() 获取该 name 对应的完整 so 文件,之后再调用 loadLibrary0() 继续
- 当 ClassLoader 不存在,分别到 system、usr 字符串数组中查找该 so 是否存在
- loadLibrary0() 将调用 native 方法 findBuiltinLib() 检查是否是内置的动态链接库,并到加载过 vector、加载中 context 中查找是否已经加载过、加载中
- 通过检查的话调用 NativeLibrary 静态内部类继续,事实上是调用 ClassLoader.c 的 load()
- 其将调用 jvm.cpp 的 JVM_LoadLibrary() 进行 so 的加载获得指针
- 根据 OS 的实现,dll_load() 通过 dlopen() 执行 so 的打开和地址返回
- 最后通过 findJniFunction() 获取 JNI_OnLoad() 地址进行 native 方法的注册和所需 JNI 版本的收集 。
原文链接:
https://mp.weixin.qq.com/s/HVQvjDhhUuCrkBuOP8PJZw
推荐阅读
- 一篇讲明白DevOps时代下的持续架构实践
- HTTP缓存看这一篇就够了
- |紫砂壶不挂水就不是好壶吗?
- 天津市|职场人的仕途,无非就是这三个阶段
- 2月逛花市,就选四种漂亮花,浇点水就能活,花开一整年
- 5种花一晒就蔫,放暗处越长越绿,养不好都是弄反了
- 市场营销专业就业方向怎么样,最新市场营销专业当前的就业形势分析
- |老婆打疫苗非要穿露肩连衣裙,戴着口罩就不怕丢脸了吗?
- 出口营销策划方案怎么做,未来出口营销就业前景
- 贺兰山|自己一知半解,却嘲讽壮壮没文化。那就说说《满江红》的贺兰山吧
