views:

538

answers:

1

I have a problem in Java where I set up a dynamic proxy with a JMX interface, pass this on to another component which then makes calls to the proxy object. When I do this, the application leaks two threads for each call, threads which never seem to time out and keep building up until the application runs out of memory.

The threads appear in pairs, see stacktrace at the bottom.

I have tried using some slightly obscure system properties to turn off timeouts alltogether in JMX but it doesn't make a difference. The key action seems to be the dynamic proxy call. The object that is called through the proxy implements Serializable so that shouldn't be a problem.

When I manually create a Bean with a string of the MBean path and the object interface and call the method from that, the problem disappears.

I am mostly looking for classic gotchas here when it comes to dynamic proxies since I don't have too much experience with them.

This is how the proxyinstance is created

public <T> T create(final Class<T> type,
        final Object... nameParameters) throws JmxConnectionException {
    return type.cast(Proxy.newProxyInstance(
            type.getClassLoader(),
            new Class< ? >[] {type},
            new MyInvocationHandler(this,
                    fill(nameOf(type), nameParameters))));
}

and the implementation of MyInvocationHandler:

final class MyInvocationHandler implements InvocationHandler, Serializable {
private static final long serialVersionUID = 0L; //actually a proper random long
private final transient ProxyFactory proxyFactory;
private String mBeanName;
private RemoteObject remoteObject;

MyInvocationHandler(final ProxyFactory proxyFactory,
        final String mBeanName) {
    this.proxyFactory = proxyFactory;
    this.mBeanName = mBeanName;
}

private void writeObject(final ObjectOutputStream out)
throws IOException {
    try {
        checkConnected();
    } catch (final JmxConnectionException e) {
        throw new IOException(e);
    }
    out.writeObject(mBeanName);
    out.writeObject(remoteObject);
}

private void readObject(final ObjectInputStream in)
throws IOException, ClassNotFoundException {
    mBeanName = (String) in.readObject();
    remoteObject = (RemoteObject) in.readObject();
}

public Object invoke(final Object proxy, final Method method,
        final Object[] args) throws Throwable {
    checkConnected(); //Just checks that the RemoteObject isn't null.
    try {
        return invokeMethod(method, args); // Calls the method on the remoteObject with the arguments, code cut.
    } catch (final InvocationTargetException e) {
        throw e.getCause();
    }
}

}

Thread stacktrace for the two threads (always appear in pairs):

Name: JMX server connection timeout 53
State: TIMED_WAITING on [I@18bbe70
Total blocked: 3  Total waited: 4

Stack trace: 
java.lang.Object.wait(Native Method)
com.sun.jmx.remote.internal.ServerCommunicatorAdmin$Timeout.run(ServerCommunicatorAdmin.java:150)
java.lang.Thread.run(Thread.java:619)

Name: Thread-21
State: TIMED_WAITING
Total blocked: 0  Total waited: 1

Stack trace: 
java.lang.Thread.sleep(Native Method)
com.sun.jmx.remote.internal.ClientCommunicatorAdmin$Checker.run(ClientCommunicatorAdmin.java:154)
java.lang.Thread.run(Thread.java:619)
+2  A: 

The problem has been solved. The problem appears during serialization of an object below RemoteObject.

When you do:

JMXConnectorFactory.connect(url)

Make sure to close it when you're done using it rather than leaving it up to garbage collection or it seems they can keep piling up...

Stefan Thyberg