Uploaded image for project: 'Weld'
  1. Weld
  2. WELD-2416

Memory behaviour of of javax.enterprise.inject.Instance<?>.iterator().next vs. of javax.enterprise.inject.Instance<?>.get() in Weld 1.1.18 vs. Weld 2.3.5

    XMLWordPrintable

Details

    • Bug
    • Resolution: Won't Do
    • Major
    • None
    • None
    • None
    • None
    • Hide
      1. Build the attached TestCDIInjection project using mvn clean install
      2. Deploy the application on application servers packaging (1) Weld 1.1.18 (e.g., WebLogic 12.1.3) and (2) Weld 2.3.5 (e.g., WildFly 10.1)
      3. Call the servlet in its current form (http://localhost:8080/CDITest-1-SNAPSHOT/Servlet)
      4. Open JMC and look at the heap histogram - check the amount of instances of the de.retit.test.CDIBean
      5. Modify the application to use iterator().next() to get the bean deploy it on both environments
      6. Call the servlet in the adapted form (http://localhost:8080/CDITest-1-SNAPSHOT/Servlet)
      7. Open JMC and look at the heap histogram - check the amount of instances of the de.retit.test.CDIBean for Weld 2.3.5 and the absence of this class in Weld 1.1.18
      Show
      Build the attached TestCDIInjection project using mvn clean install Deploy the application on application servers packaging (1) Weld 1.1.18 (e.g., WebLogic 12.1.3) and (2) Weld 2.3.5 (e.g., WildFly 10.1) Call the servlet in its current form ( http://localhost:8080/CDITest-1-SNAPSHOT/Servlet ) Open JMC and look at the heap histogram - check the amount of instances of the de.retit.test.CDIBean Modify the application to use iterator().next() to get the bean deploy it on both environments Call the servlet in the adapted form ( http://localhost:8080/CDITest-1-SNAPSHOT/Servlet ) Open JMC and look at the heap histogram - check the amount of instances of the de.retit.test.CDIBean for Weld 2.3.5 and the absence of this class in Weld 1.1.18

    Description

      In a recent performance test we have noticed a memory leak while using CDI Instance injections on WebLogic 12.1.3 (packaging Weld 1.1.18) and noticed some memory-relevant behaviour differences when comparing it to a more recent Weld version 2.3.5 packaged in Wildfly 10.1. The basic question comes down to wether javax.enterprise.inject.Instance<?>.iterator().next() should behave differently to javax.enterprise.inject.Instance<?>.get() as it did in Weld 1.1.18 or more similarly as they do in Weld 2.3.5?

      Here are some more details:

      The simplest setup we could boil this issue down to is the following web application (also attached as maven project TestCDIInjection.zip):

      @WebServlet("/Servlet")
      public class Servlet extends HttpServlet {
      	private static final long serialVersionUID = 1L;
      
      	@Inject
      	private Instance<CDIInterface> cdi;
      	/**
      	 * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
      	 */
      	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      		response.getWriter().write("Here " + Servlet.class.getName() + " - " + cdi.get().sayHello());
      	}
      
      }
      
      public interface CDIInterface {
      
      	public abstract String sayHello();
      }
      
      @Default
      public class CDIBean implements CDIInterface{
      
      	@Inject
      	private Instance<CDIBean2> bean2;
      	
      	public String sayHello() {
      		return "Here " + CDIBean.class.getName() + "  - " + bean2.get().testHello();
      	}
      
      }
      
      public class CDIBean2 {
      
      	public String testHello() {
      		return "Here " + CDIBean2.class.getName();
      	}
      }
      

      In this web application the amount of CDIBean instances keeps growing for each Servlet invocation, however, this is not happening if the CDIBean would not reference the CDIBean2 in Weld 1.1.18 on Weblogic 12.1.3. Here you can see the resut of 8 Servlet invocations:

      After some investigations and looking at similar tickets (such as this one: https://issues.jboss.org/browse/WELD-1478) and blog articles (https://blog.akquinet.de/2017/01/04/dont-get-trapped-into-a-memory-leak-using-cdi-instance-injection/) we came up with a slightly different work around which is to use javax.enterprise.inject.Instance<?>.iterator().next() instead of javax.enterprise.inject.Instance<?>.get() in order to retreive the CDI instance we are interested in.

      If you just change the get() calls to iterator().next() in the code snippets above the instances will be garbage collected, e.g.:

      response.getWriter().write("Here " + Servlet.class.getName() + " - " + cdi.iterator().next().sayHello());
      

      You can call the servlet as often as you want and you will only see the Servlet instance in memory as expected.

      In order to ensure hat this solution makes any sense, we have also tried it on a newer Weld version (2.3.5) with WildFly 10.1 and noticed that the behaviour does not differ anymore between the get() and iterator().next() calls.

      So what behaviour is the expected one? One major change we have noticed in the InstanceImpl.iterator() implementation between the two versions we have tested (1.1.18 and 2.3.5) is the following commit:

      https://github.com/weld/core/commit/4f5eb3b95ebb815d3fbf0a1cb67ebbb11700af43#diff-e5101dc08bd36449a7b95c85e482075e

      to fix:

      https://issues.jboss.org/browse/WELD-1320

      However, with the changed iterator() behaviour, we are running in a memory leak with both solutions. Is there any chance for a fix for WELD-1320 that still leads to the old memory behaviour behaviour of InstanceImpl.iterator()?

      Attachments

        Activity

          People

            Unassigned Unassigned
            brunnert Andreas Brunnert (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: