2012-12-24 20 views
11

私は単純なJavaプロファイラを作成し、これに対してClassLoaderを使用しようとしています。私はこの出力を受け取り、このクラスローダを使用しようとしたらRMI呼び出しを伴うClassLoader

import java.rmi.RemoteException; 
import java.rmi.registry.LocateRegistry; 
import java.rmi.registry.Registry; 

public class CustomClassLoader extends ClassLoader { 
    private Notifier notifier; 

    public CustomClassLoader() { 
     super(); 
    } 

    public CustomClassLoader(ClassLoader parent) { 
     super(parent); 
    } 

    private void initNotifier() { 
     if (notifier != null) return; 
     try { 
      System.out.println("2"); 
      Registry registry = LocateRegistry.getRegistry(Const.registryPort); 
      System.out.println("3"); 
      notifier = (Notifier) registry.lookup(Const.stubName); 
      System.out.println("4"); 
     } catch (Exception e) { 
      e.printStackTrace(); 
      System.exit(1); 
     } 
    } 

    @Override 
    protected synchronized Class<?> loadClass(String name, boolean resolve) 
            throws ClassNotFoundException { 
     System.out.println("0"); 
     Class clazz = super.loadClass(name, resolve); 
     System.out.println("1"); 
     initNotifier(); 
     System.out.println("5"); 
     try { 
      notifier.classLoaded(name); 
      System.out.println("6"); 
     } catch (RemoteException e) { 
      e.printStackTrace(); 
      System.exit(1); 
     } 
     return clazz; 
    } 
} 

(私は1.6_37と1.7_10 JKDを使用しようとしました):

これはクラスローダの私の実装です

C:\Users\Scepion1d>java -cp C:\Users\Scepion1d\Dropbox\Workspace\IntellijIDEA\pr 
ofiler\out\artifacts\loader\loader.jar;C:\Users\Scepion1d\Dropbox\Workspace\Inte 
llijIDEA\app\out\production\app -Djava.system.class.loader=CustomClassLoader Main 
0 
1 
2 
0 
1 
2 
3 
0 
1 
2 
3 
java.lang.IllegalArgumentException: Non-positive latency: 0 
     at sun.misc.GC$LatencyRequest.<init>(GC.java:190) 
     at sun.misc.GC$LatencyRequest.<init>(GC.java:156) 
     at sun.misc.GC.requestLatency(GC.java:254) 
     at sun.rmi.transport.DGCClient$EndpointEntry.lookup(DGCClient.java:212) 
     at sun.rmi.transport.DGCClient.registerRefs(DGCClient.java:120) 
     at sun.rmi.transport.ConnectionInputStream.registerRefs(ConnectionInputS 
tream.java:80) 
     at sun.rmi.transport.StreamRemoteCall.releaseInputStream(StreamRemoteCal 
l.java:138) 
     at sun.rmi.transport.StreamRemoteCall.done(StreamRemoteCall.java:292) 
     at sun.rmi.server.UnicastRef.done(UnicastRef.java:431) 
     at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source) 
     at CustomClassLoader.initNotifier(CustomClassLoader.java:22) 
     at CustomClassLoader.loadClass(CustomClassLoader.java:35) 
     at java.lang.ClassLoader.loadClass(ClassLoader.java:247) 
     at sun.security.jca.ProviderConfig$3.run(ProviderConfig.java:234) 
     at java.security.AccessController.doPrivileged(Native Method) 
     at sun.security.jca.ProviderConfig.doLoadProvider(ProviderConfig.java:22 
5) 
     at sun.security.jca.ProviderConfig.getProvider(ProviderConfig.java:205) 
     at sun.security.jca.ProviderList.getProvider(ProviderList.java:215) 
     at sun.security.jca.ProviderList.getService(ProviderList.java:313) 
     at sun.security.jca.GetInstance.getInstance(GetInstance.java:140) 
     at java.security.Security.getImpl(Security.java:659) 
     at java.security.MessageDigest.getInstance(MessageDigest.java:129) 
     at java.rmi.dgc.VMID.computeAddressHash(VMID.java:140) 
     at java.rmi.dgc.VMID.<clinit>(VMID.java:27) 
     at sun.rmi.transport.DGCClient.<clinit>(DGCClient.java:66) 
     at sun.rmi.transport.ConnectionInputStream.registerRefs(ConnectionInputS 
tream.java:80) 
     at sun.rmi.transport.StreamRemoteCall.releaseInputStream(StreamRemoteCal 
l.java:138) 
     at sun.rmi.transport.StreamRemoteCall.done(StreamRemoteCall.java:292) 
     at sun.rmi.server.UnicastRef.done(UnicastRef.java:431) 
     at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source) 
     at CustomClassLoader.initNotifier(CustomClassLoader.java:22) 
     at CustomClassLoader.loadClass(CustomClassLoader.java:35) 
     at java.lang.ClassLoader.loadClass(ClassLoader.java:247) 
     at sun.security.jca.ProviderConfig$3.run(ProviderConfig.java:234) 
     at java.security.AccessController.doPrivileged(Native Method) 
     at sun.security.jca.ProviderConfig.doLoadProvider(ProviderConfig.java:22 
5) 
     at sun.security.jca.ProviderConfig.getProvider(ProviderConfig.java:205) 
     at sun.security.jca.ProviderList.getProvider(ProviderList.java:215) 
     at sun.security.jca.ProviderList$3.get(ProviderList.java:130) 
     at sun.security.jca.ProviderList$3.get(ProviderList.java:125) 
     at java.util.AbstractList$Itr.next(AbstractList.java:345) 
     at java.security.SecureRandom.getPrngAlgorithm(SecureRandom.java:522) 
     at java.security.SecureRandom.getDefaultPRNG(SecureRandom.java:165) 
     at java.security.SecureRandom.<init>(SecureRandom.java:133) 
     at java.rmi.server.UID.<init>(UID.java:92) 
     at java.rmi.server.ObjID.<clinit>(ObjID.java:71) 
     at java.rmi.registry.LocateRegistry.getRegistry(LocateRegistry.java:158) 

     at java.rmi.registry.LocateRegistry.getRegistry(LocateRegistry.java:106) 

     at java.rmi.registry.LocateRegistry.getRegistry(LocateRegistry.java:73) 
     at CustomClassLoader.initNotifier(CustomClassLoader.java:20) 
     at CustomClassLoader.loadClass(CustomClassLoader.java:35) 
     at java.lang.ClassLoader.loadClass(ClassLoader.java:247) 

問題はRMIサーバーにあると思っていましたが、別のRMIクライアントを作成していて、うまくいきます。 誰がどこに問題があるのか​​、それを解決する方法を知っていますか?

+1

別の(新しいバージョンまたは別のバージョンの)Javaを試してみてください。役立たない場合は、バグを提出してください。 – tcb

+1

これは実際には偶発的な再帰です。スタックトレースをよく見てください。クラスローダーを過度に使用しているようです。 – EJP

+0

それをさらに追跡するには、あなたのprintlnに 'name'を" 0 "として追加することもできます。 – JoshDM

答えて

2

TL; DR:ルートクラスローダーのような重い副作用があるクラスローダーは使用しないでください。

問題は、sun.rmi.transport.DGCClientクラスのconstフィールドgcIntervalが使用される前に初期化されていない(したがって値0を示しています)。これは、クラスローダーがRMI経由で呼び出しを行い、DGCClientの新しいインスタンスを作成するためです。 DGCClientのコンストラクタの実行中に別のクラスがロードされます(スタックトレースを参照)。この3回目のクラスローダー呼び出しは、DGCClientの新しいインスタンスを作成せずに以前に作成したものを使用し、その上で呼び出しを行うRMI呼び出しを再度トリガーします。つまり、初期化されていないオブジェクトの呼び出しが行われ、この初期化されていない定数フィールドが使用されます。

すべてのJavaクラスは、このような予期しない副作用なしにロードされていると想定できるため、Sun/Oracleにこれを責めることはできません。