11

シンプルな Java プロファイラーを作成しようとしており、これには ClassLoader を使用しています。

これは 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 クライアントを作成したところ、問題なく動作しました。問題がどこにあり、それを解決する方法を知っている人はいますか?

4

1 に答える 1

2

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

問題は、sun.rmi.transport.DGCClient クラスの const フィールド gcInterval が使用前に初期化されないことです (したがって、値 0 が表示されます)。これは、クラス ローダーが RMI を介して呼び出しを行い、DGCClient の新しいインスタンスを作成するためです。DGCClient のコンストラクターの実行中に、別のクラスがロードされます (スタック トレースを参照)。このクラス ローダーへの 3 回目の呼び出しにより、RMI 呼び出しが再びトリガーされます。これは、DGCClient の新しいインスタンスを作成するのではなく、以前に作成されたインスタンスを使用して、その上で何らかの呼び出しを行います。これは、半分初期化されたオブジェクトに対して呼び出しが行われ、このまだ初期化されていない定数フィールドが使用されることを意味します。

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

于 2013-01-04T09:17:31.523 に答える