我有一个类调用本机函数来从CMOS获取有关系统的信息。该类有一个静态初始化块,它加载包含本机函数的库,它看起来像这样:
package lib.sysid;
public class SysId
{
private static native int getSysIdNative();
private static final String SYS_ID_PATH = "libsysid.so";
static
{
System.load(SYS_ID_PATH);
}
public static int getSysIdFromCMOS()
{
int returnValue = getSysIdNative();
}
}
根据我的测试,该方法在我第一次使用时工作正常,但如果我稍后再次调用该方法,静态初始化块也会运行,导致UnsatisfiedLinkError:
java.lang.UnsatisfiedLinkError: Native Library libsysid.so already loaded in another classloader
如果已经运行了System.load()
方法,如何避免静态初始化块执行?
或者,如果已经加载了库,那么在我再次调用System.load()
方法之前,是否有办法尝试“卸载”该文件?
编辑:奇怪的是,如果我用try-catch块包围System.load()
调用,我仍然会得到一个UnsatisfiedLinkError,但这次它来自对getSysIdNative()
的实际调用。我看到的错误如下:
lib.sysid.SysId.getSysIdNative()I
出现的“我”到底是什么?我试图将调试器附加到此代码以查看消息的填充位置,但到目前为止我还没有成功。
答案 0 :(得分:2)
只是一个猜测,但我认为单个JVM加载类(并执行其静态初始化程序)两次的唯一方法是使用不同的类加载器加载它。所以这里可能有第二个类加载器,你不知道。如果第二次有不同的(一组)类加载器生效,这将适用。
在“真实”操作系统下,java -verbose:class
将为您提供加载程序消息以验证此操作。我不确定你是如何在嵌入式系统上验证这一点的。您可以修改getSysId()
以打印(?)或以某种方式转储对SysId.class.getClassLoader()
的引用。
答案 1 :(得分:0)
我认为@Carl是对的。静态初始化程序在JVM中运行两次的唯一方法是在多个类加载器中加载类。
lib.sysid.SysId.getSysIdNative()I
那么“我”出现了什么?
这很容易。 I
基于由类文件格式定义的签名中类型的内部表示。特别是,I
表示原始int
类型;请参阅Class.getName()等。这与您方法的返回类型相符。
(这些原始类型名称偶尔出现在应用程序空间中有点令人困惑,但它们确实存在。另一种可以看到它们的情况是当你在继承方法实现的类上调用toString()
时来自Object
类。)