I am using Instance as a lazy / dynamic injector in a TomEE Java application, and I have noticed a memory leak in my application. This is a first for me, so it's actually surprising to see a memory leak warning that has been outlined in the Java EE Library :
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);
}
Now this is most likely being caused by a clash with @ApplicationScoped
and the Instance<T>
. I've provided an example of how the layers are in my classes. Notice the nested Instance<T>
. This is to provide dynamic injection of tasks.
Outer Class
@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);
}
// ...
}
Inner Class
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.
}
// ...
}
Interface
public interface Task<T> {
void doTask();
void setObject(T obj);
}
The classes that are leaking without calling destroy(T instance)
are ExampleObject
, Worker<T>
, and the implementation of Task<T>
. To keep the async design, I have tried passing the instance of Worker<T>
within it's instance (probably a bad idea, but I tried anyways), calling destroy(T instance)
and setting ExampleObject
to null
. This cleaned up the Task<T>
implementation and ExampleObject
, but not Worker<T>
.
Another test I tried was doing a synchronous design within MessageListenerImpl
(i.e. removing Worker<T>
and using Task<T>
) as a fallback effort, calling destroy(T instance)
to clean up. This STILL left the leak, which leads me to believe it's got to be the clash with @ApplicationScoped
and the Instance<T>
.
If there is a way to keep the async design while achieving no memory leaks, please let me know. Really appreciate feedback. Thanks!
Instance
you have to make sure your instances are destroyed, especially when it comes to@Dependent
scope. – Tattle