JNI - 我可以在不调用 System.loadLibrary 的本地插件的情况下使用 RegisterNatives 吗?

Posted

技术标签:

【中文标题】JNI - 我可以在不调用 System.loadLibrary 的本地插件的情况下使用 RegisterNatives 吗?【英文标题】:JNI - Can I use RegisterNatives without calling System.loadLibrary for native plugins? 【发布时间】:2013-11-23 10:37:59 【问题描述】:

我有一个使用插件的 C++ 应用程序(它动态加载某些共享库文件)。我无法理解从 Java 调用动态加载的本机代码需要做什么。

我是否必须使用 System.loadLibrary/System.load 来“预加载”本机共享对象(“插件”)以便能够调用该本机代码?或者我可以只在插件中调用 RegisterNatives 在我的本机代码中加载它之后?我已经为我的主要本机应用程序库调用了 System.loadLibrary - 它是本机库加载的后续插件。

如果我只调用 RegisterNatives 就可以逃脱,如果我突然决定卸载插件并且 JVM 尝试调用其中的本机方法会发生什么?

【问题讨论】:

【参考方案1】:

至少 android VM 要求在实例化类时必须“注册”所有本机方法。这就是为什么System.load() 通常在静态构造函数中调用,而不是稍后调用。

解析本机方法的两种方法是通过JNI_OnLoad() 中的RegisterNatives() 或通过名称匹配(javah 报告的 C 导出函数名称)。

您可以在所有加载的模块中查找RegisterNatives() 的函数指针,或者加载更多模块并从中获取指针。 RegisterNatives()可以随时调用,如果你真的想卸载一些插件可以使用UnregisterNatives()

引入后者是为了支持以下流程(伪代码如下):

SwitchPlugin() 
    UnregisterNatives();
    unloadPlugin(oldHandle);
    newHandle = loadPlugin(newPluginName);
    RegisterNatives();

如果您的应用尝试使用在未加载的插件中实现的本机方法,或者在使用 UnregisterNatives() 注销后,您的应用可能会严重崩溃。

【讨论】:

我不相信最初的句子是真的,好像它是,声明一个本地方法并在以后(但在使用之前)加载实现是行不通的。事实上确实如此,如果跳过加载,运行时异常只会在尝试使用缺失的方法时发生,不会在实例化它所属的类时发生。跨度> @chris-stratton:你说的是 Android 实现吗? 只要我事先加载了所有的类 id,在加载原生插件后调用 RegisterNatives 似乎工作正常

以上是关于JNI - 我可以在不调用 System.loadLibrary 的本地插件的情况下使用 RegisterNatives 吗?的主要内容,如果未能解决你的问题,请参考以下文章

System.load()与System.loadLibrary()

System.load(String filename)和System.loadLibrary(String libname)的区别

我可以在 Java 中控制 JNI 本机方法调用名称吗?

JNI - 我可以在不调用 System.loadLibrary 的本地插件的情况下使用 RegisterNatives 吗?

ubuntu下使用JNI Java调用C++的例子

System.load() 方法在不设置 LD_LIBRARY_PATH 环境变量的情况下不加载共享库