【发布时间】:2018-03-20 15:49:47
【问题描述】:
我在 TomEE Java 应用程序中使用 Instance 作为惰性/动态注入器,我注意到我的应用程序中存在内存泄漏。这对我来说是第一次,所以看到 Java EE 库中概述的内存泄漏警告确实令人惊讶:
package javax.enterprise.inject;
public interface Instance<T> extends Iterable<T>, Provider<T>
{
/**
* Destroy the given Contextual Instance.
* This is especially intended for {@link javax.enterprise.context.Dependent} scoped beans
* which might otherwise create mem leaks.
* @param instance
*/
public void destroy(T instance);
}
现在这很可能是由与 @ApplicationScoped 和 Instance<T> 的冲突引起的。我已经提供了一个示例,说明图层在我的类中是如何存在的。注意嵌套的Instance<T>。这是为了提供任务的动态注入。
外部类
@ApplicationScoped
public class MessageListenerImpl implements MessageListener {
@Resource(name="example.mes")
private ManagedExecutorService mes;
@Inject @Any
private Instance<Worker<ExampleObject>> workerInstance;
// ...
@Override
public void onMessage(Message message) {
ExampleObject eo = new ExampleObject();
Worker<ExampleObject> taskWorker = workerInstance.get();
taskWorker.setObject(eo);
mes.submit(taskWorker);
}
// ...
}
内部类
public class Worker<T> implements Runnable {
@Inject @Any
private Instance<Task> taskInstance;
@Setter
private T object
// ...
@Override
public void run() {
Task t = taskInstance.get();
t.setObject(object);
t.doTask();
// Instance destruction, manual cleanup tried here.
}
// ...
}
界面
public interface Task<T> {
void doTask();
void setObject(T obj);
}
不调用destroy(T instance)而泄漏的类有ExampleObject、Worker<T>和Task<T>的实现。为了保持异步设计,我尝试在它的实例中传递Worker<T> 的实例(可能是个坏主意,但我还是尝试了),调用destroy(T instance) 并将ExampleObject 设置为null。这清理了Task<T> 实现和ExampleObject,但不是Worker<T>。
我尝试的另一个测试是在 MessageListenerImpl 中进行同步设计(即删除 Worker<T> 并使用 Task<T>)作为后备工作,调用 destroy(T instance) 进行清理。这仍然留下了漏洞,这让我相信这一定是与 @ApplicationScoped 和 Instance<T> 的冲突。
如果有办法在保持异步设计的同时避免内存泄漏,请告诉我。非常感谢反馈。谢谢!
【问题讨论】:
标签: jakarta-ee memory-leaks garbage-collection cdi apache-tomee