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!