SecurityAssociation.threadSubjectStacks leaks when TimerServ
alexeinov Aug 11, 2009 4:58 PMSubject stack grows infinitely in SecurityAssociation when timer is called. Memory allocated to stack is never freed, which is a memory leak that after a while leads to OutOfMemory condition.
I tried to run the following code in JBoss 4.2.3 GA as well as in Branch_4_2. I can see that the objects count of the class org.jboss.security.SecurityAssociation$SubjectContext grows by two with each timer call. This is the code:
package mbean; import org.jboss.annotation.ejb.Management; @Management public interface TimerAuthMBean { void start() throws Exception; }
import javax.annotation.Resource; import javax.ejb.Timeout; import javax.ejb.Timer; import javax.ejb.TimerService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jboss.annotation.ejb.Service; @Service(name = "TimerAuthenticationTest") public class TimerAuthMBeanImpl implements TimerAuthMBean { private Log log = LogFactory.getLog(this.getClass()); @Resource private TimerService timerService; public void start() { timerService.createTimer(10000, 3000, "FooTimer"); } @Timeout public void onTime(final Timer timer) { log.debug("Timer called"); } }
Further profiling have shown that calls to push() and pop() methods are not balanced when the above code is running. There are two extra push() calls that are never backed with pop() calls. Here are push() and pop() methods in SecurityAssociations$SubjectThreadLocalStack:
private static class SubjectThreadLocalStack { ... void push(SubjectContext context) { ArrayList stack = (ArrayList) local.get(); stack.add(context); } ... SubjectContext pop() { ArrayList stack = (ArrayList) local.get(); SubjectContext context = null; int lastIndex = stack.size() - 1; if (lastIndex >= 0) context = (SubjectContext) stack.remove(lastIndex); return context; } }
These two extra push() calls are initiated from the callTimeout() method in org.jboss.ejb3.service.ServiceContainer class. This method calls SecurityAssociation.setPrincipal(), which pushes the subject thread, and does nothing to set it back. Looks strange to me.
Is this a bug or am I missing some part of configuration? Are there workarounds?
I could not think about something better than to pop the subjects stack forcefully from my timer code like this:
SecurityAssociation.popSubjectContext(); SecurityAssociation.popSubjectContext();