I trying to make simple java profiler and using ClassLoader for this.
This is my implementation of 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;
}
}
When i've try to use this class loader i receive this output (I've tried to use 1.6_37 and 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)
I've thought that problem is in the RMI server, but i wrote another RMI client and it works good. Does anyone know where is the problem(s) and how to solve it(them)?
TL;DR: Don't use a class loader which such heavy side effects as the root class loader.
The problem is that the const field gcInterval on class sun.rmi.transport.DGCClient is not initialized before it's used (and hence shows value 0). The reason for this is that your class loader makes the call via RMI which creates a new instance of DGCClient. During the execution of the constructor of DGCClient another class is loaded (see stack trace). This third call to the class loader triggers the RMI call again which doesn't create a new instance of DGCClient but uses the previously created one and does some call on it. That means that a call is made on a half-initialized object which leads to the use of this not-yet initialized constant field.
We can't possibly blame Sun/Oracle for this since every Java class can assume that it is loaded without such unpredictable side effects.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With