Details
-
Bug
-
Resolution: Won't Do
-
Major
-
None
-
None
-
None
-
None
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:
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()?