Search code examples
javadependency-injectionrcpe4

Memory Leak / ContextInjectionFactory / IEclipseContext


I am using dependency injection (DI) inside an Eclipse RCP application. I have a lot of classes that perform code similar to below:

public class SomeClass {
    @Inject
    private IEclipseContext context;

    private SomeObject void someMethod(){
        SomeObject someObject =
            ContextInjectionFactory.make(SomeObject.class, context);
        // Do stuff with someObject
    }
 }

When I monitor the application using jvisualvm, I notice there is a memory leak due to this. The EclipseContext object keeps growing until it eventually runs out of memory.

If I do the following, the memory leak goes away:

public class SomeClass {
    @Inject
    private IEclipseContext context;

    private SomeObject void someMethod(){
        IEclipseContext childContext = context.createChild();
        SomeObject someObject =
            ContextInjectionFactory.make(SomeObject.class, childContext);
        childContext.dispose();
        // Do stuff with someObject
    }
 }

I have not seen any documentation that supports doing my workaround. Is there any negative side effects to disposing the childContext after the class is created? Is there a better approach overall when using CIF that I haven't encountered?

For what it's worth, my code has many classes, some of which are annotated with @Singleton / @Creatable. I'm not sure if these would be effected by a disposed parent context.

Thanks!


Solution

  • When you use injection to set fields in your class like this:

    public class Test
    {
      @Inject
      private StatusReporter rep;
      @Inject
      private IEventBroker broker;
    
    
      public Test()
      {
      }
    }
    

    Eclipse must track each field that has been injected so that it can reinject the field if the value in the Eclipse Context changes. This involves creating TrackableComputationEx‌​t and ‌​ContextInjectionList‌​ener objects for each injected field.

    If instead you inject the values in the constructor like this:

    public class Test
    {
      private StatusReporter rep;
      private IEventBroker broker;
    
      @Inject
      public Test(StatusReporter rep, IEventBroker broker)
      {
        this.rep = rep;
        this.broker = broker;
      }
    }
    

    Eclipse has no need to track Constructor injection so these objects are not created (but you also won't get any updates if the context values are changed).

    Testing this there does still seem to be one internal use tracking object created.