2010-07-26 4 views
1

J'ai une classe qui appelle une fonction native pour obtenir des informations sur un système à partir de son CMOS. La classe a un bloc d'initialisation statique qui charge la bibliothèque contenant la fonction native, et il ressemble à ceci:Comment puis-je éviter d'appeler System.load deux fois?

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(); 
    } 
} 

Selon mes tests, la méthode fonctionne très bien la première fois que je l'utilise, mais si je l'appelle la méthode à nouveau à une date ultérieure, le bloc d'initialisation statique fonctionne également, ce qui provoque une UnsatisfiedLinkError:

java.lang.UnsatisfiedLinkError: Native Library libsysid.so already loaded in another classloader 

Comment puis-je éviter le bloc d'initialisation statique d'exécuter la méthode System.load() si elle a déjà été exécuté?

Sinon, est-il possible de tenter de "décharger" la bibliothèque si elle est déjà chargée avant d'appeler à nouveau la méthode System.load()? EDIT: Bizarrement, si j'entoure l'appel System.load() avec un bloc try-catch, j'obtiens toujours une UnsatisfiedLinkError, mais cette fois-ci, elle provient de l'appel réel getSysIdNative(). L'erreur que je vois est la suivante:

lib.sysid.SysId.getSysIdNative()I 

Que diable est ce "I" qui apparaît? J'ai essayé d'attacher un débogueur à ce code pour voir où le message est rempli, mais jusqu'ici je n'ai pas réussi.

Répondre

2

Juste une supposition, mais je pense que la seule façon pour une seule machine virtuelle Java pour charger une classe (et exécuter ses initialiseurs statiques) est deux fois pour le charger avec différentes classloaders. Il se peut donc qu'il y ait un second classloader impliqué ici que vous ne connaissez pas. Cela s'applique si un (ensemble de) classloader (s) différent (s) est en vigueur la deuxième fois.

En vertu d'un système d'exploitation « réel », java -verbose:class vous donnerait chargeur messages pour vérifier cela avec. Je ne suis pas sûr de savoir comment procéder pour vérifier cela sur un système embarqué. Vous pouvez modifier getSysId() pour imprimer (?) Ou en quelque sorte vider une référence à SysId.class.getClassLoader().

0

Je pense que @Carl est juste. La seule façon qu'un initiateur statique peut exécuter deux fois dans une machine virtuelle Java est si la classe est chargée dans plusieurs chargeurs de classe.

lib.sysid.SysId.getSysIdNative()I What the heck is that "I" that shows up?

C'est facile. Le I est basé sur la représentation interne des types dans les signatures qui est définie par le format de fichier de classe. En particulier, I signifie le type primitif int; voir Class.getName(), etc. Cela correspond au type de retour de votre méthode.

(Il est un peu déroutant que ces noms de type primitif apparaissent occasionnellement dans l'espace application, mais ils le font.Un autre cas où vous pouvez les voir est lorsque vous appelez toString() sur une classe qui hérite de l'implémentation de la méthode Object classe.)

+0

C'est exactement le problème que je vois. Il y a une certaine logique dans le système que j'utilise qui "recharge" tous les fichiers de bibliothèque associés au système, y compris le fichier ci-dessus, mais il le fait via un chargeur de classe différent de celui qui charge les fichiers. – troyal