如何避免两次调用System.load?

时间:2010-07-26 20:01:22

标签: java java-native-interface

我有一个类调用本机函数来从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

出现的“我”到底是什么?我试图将调试器附加到此代码以查看消息的填充位置,但到目前为止我还没有成功。

2 个答案:

答案 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类。)