使用 jmx 的动态代理会导致线程泄漏吗?
我在 Java 中遇到一个问题,我使用 JMX 接口设置动态代理,将其传递给另一个组件,然后该组件调用代理对象。 当我这样做时,应用程序会为每个调用泄漏两个线程,这些线程似乎永远不会超时并不断建立,直到应用程序耗尽内存。
线程成对出现,请参阅底部的堆栈跟踪。
我尝试过使用一些稍微晦涩的系统属性来关闭 JMX 中的超时,但这没有什么区别。 关键操作似乎是动态代理调用。 通过代理调用的对象实现了可序列化,因此这应该不是问题。
当我使用 MBean 路径和对象接口的字符串手动创建 Bean 并从中调用方法时,问题就消失了。
当涉及到动态代理时,我主要在这里寻找经典的陷阱,因为我对它们没有太多的经验。
这就是代理实例的创建方式
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))));
}
以及 MyInitationHandler 的实现方式:
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();
}
}
}
两个线程的线程堆栈跟踪(始终成对出现):
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)
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)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题已经解决了。 在序列化 RemoteObject 下面的对象期间会出现该问题。
当您创建 JMXConnector 时,使用完后一定要关闭它,而不是将其留给垃圾收集,否则它们似乎会继续堆积......
The problem has been solved. The problem appears during serialization of an object below RemoteObject.
When you create a JMXConnector, 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...