EJB Stateful Session Beans – Where did the Garbage Collector go?
Summary: Asking the developer to call the "remove" method on a stateful session bean is as bad as the "delete" operator in C++. We’ve got garbage collection with POJOs. Why did we revert to manual instance management with EJBs?
For many years I've been avoiding Java Enterprise Edition. It seemed rather pointless to me. It was supposed to help me to write less code (so I wouldn't have to write remoting, transactions, and stuff like that), but every time I looked at it I came to the conclusion that it would cause me to write more code. Java EE 5 seems like it might actually help me to write less code! So now I'm finally looking seriously at EJB. Therefore, I'm sure the following complaint is nothing new.
The Java language brought a number of great programming features into the mainstream. In my opinion, one of the best features popularized by Java is automatic garbage collection. This frees the developer from maintaining object instance lifecycle and memory allocation/deallocation.
It would be reasonable to assume that container-managed beans would improve and enhance object instance lifecycle management to something beyond the garbage collector. Unfortunately, to some degree container-managed Enterprise JavaBeans take us a step backwards in the area of automatic object lifecycle maintenance. More of the responsibility of managing lifecycle is back in the hands of the developer. Even the latest EJB3 spec does not seem to correct this limitation of the EBJ programming model.
Let's compare POJO instances and EJB3 Stateful Session Bean (SFSB) instances.
With a POJO, when you want an instance, you create it with the "new" operator. As long as something in your code maintains a reference to the instance, it will not be deleted and garbage collected. Once all references are removed, it is immediately available to be cleared out of memory by the garbage collector. Java supports a "finalize" callback which will be called (theoretically) before the garbage collection removes the object. (Yes, I know this is oversimplification.)
Now let's examine EJB3 Stateful Session Bean (SFSB) instances. When you want an instance, you make a JNDI lookup, which instantiates an instance of the bean in the container and a stub to you. As long as you continue to utilize methods on the stub (which are delegated to the bean), the bean will not be deleted and garbage collected. If keep a reference to the stub, but fail to make any calls to the object for a set timeout period, the object will be removed. Once all references are removed, you must still wait for the timeout period before the instance is available to be cleared out of memory by the garbage collector. If you would like the instance to be eligible for garbage collection earlier, you must call the "remove" method. EJB3 supports the PreDestory callback which will be called before the bean is destroyed.
So, with EBJ3 Stateful Session Beans, we have moved away from a reference-counted, automatically managed object instance lifecycle. We have now reverted to a developer-managed instance lifecycle with a "session timeout" tacked onto the side. The "remove" method smells a lot like a "delete" operator, putting the responsibility on the developer to destroy the instance.
Even worse than requiring the developer to delete objects, it seems that at any moment a SFSB stub could become unusable because the container-managed SFSB was removed due to a period of inactivity. Of course, the container could be configured with a longer timeout, but then resource management will not be as efficient, since unusable beans (who’s stubs have long since disappeared) may still be taking up memory in the container, passivated to disk (which burns CPU & I/O), and then finally destroyed long after they should have been destroyed.
So, how should the Stateful Session Bean lifecycle be managed? In my opinion, the lifecycle of a SFSB should follow the standard POJO lifecycle model. The actual container-managed bean instance that is behind the stub should have its lifecycle tied directly to the lifecycle of the stub. When no references to the stub remain, the SFSB should be automatically removed and become available for garbage collection. As long as a reference to the stub remains, the SFSB behind that stub should not time out (or at least I should be able to configure a really long timeout, taking comfort in the fact that the loss of the last "active" stub will cause the instance to be automatically removed before the timeout).
Do any containers actually implement the SFSB lifecycle in this way so as to avoid the "remove" method?
For many years I've been avoiding Java Enterprise Edition. It seemed rather pointless to me. It was supposed to help me to write less code (so I wouldn't have to write remoting, transactions, and stuff like that), but every time I looked at it I came to the conclusion that it would cause me to write more code. Java EE 5 seems like it might actually help me to write less code! So now I'm finally looking seriously at EJB. Therefore, I'm sure the following complaint is nothing new.
The Java language brought a number of great programming features into the mainstream. In my opinion, one of the best features popularized by Java is automatic garbage collection. This frees the developer from maintaining object instance lifecycle and memory allocation/deallocation.
It would be reasonable to assume that container-managed beans would improve and enhance object instance lifecycle management to something beyond the garbage collector. Unfortunately, to some degree container-managed Enterprise JavaBeans take us a step backwards in the area of automatic object lifecycle maintenance. More of the responsibility of managing lifecycle is back in the hands of the developer. Even the latest EJB3 spec does not seem to correct this limitation of the EBJ programming model.
Let's compare POJO instances and EJB3 Stateful Session Bean (SFSB) instances.
With a POJO, when you want an instance, you create it with the "new" operator. As long as something in your code maintains a reference to the instance, it will not be deleted and garbage collected. Once all references are removed, it is immediately available to be cleared out of memory by the garbage collector. Java supports a "finalize" callback which will be called (theoretically) before the garbage collection removes the object. (Yes, I know this is oversimplification.)
Now let's examine EJB3 Stateful Session Bean (SFSB) instances. When you want an instance, you make a JNDI lookup, which instantiates an instance of the bean in the container and a stub to you. As long as you continue to utilize methods on the stub (which are delegated to the bean), the bean will not be deleted and garbage collected. If keep a reference to the stub, but fail to make any calls to the object for a set timeout period, the object will be removed. Once all references are removed, you must still wait for the timeout period before the instance is available to be cleared out of memory by the garbage collector. If you would like the instance to be eligible for garbage collection earlier, you must call the "remove" method. EJB3 supports the PreDestory callback which will be called before the bean is destroyed.
So, with EBJ3 Stateful Session Beans, we have moved away from a reference-counted, automatically managed object instance lifecycle. We have now reverted to a developer-managed instance lifecycle with a "session timeout" tacked onto the side. The "remove" method smells a lot like a "delete" operator, putting the responsibility on the developer to destroy the instance.
Even worse than requiring the developer to delete objects, it seems that at any moment a SFSB stub could become unusable because the container-managed SFSB was removed due to a period of inactivity. Of course, the container could be configured with a longer timeout, but then resource management will not be as efficient, since unusable beans (who’s stubs have long since disappeared) may still be taking up memory in the container, passivated to disk (which burns CPU & I/O), and then finally destroyed long after they should have been destroyed.
So, how should the Stateful Session Bean lifecycle be managed? In my opinion, the lifecycle of a SFSB should follow the standard POJO lifecycle model. The actual container-managed bean instance that is behind the stub should have its lifecycle tied directly to the lifecycle of the stub. When no references to the stub remain, the SFSB should be automatically removed and become available for garbage collection. As long as a reference to the stub remains, the SFSB behind that stub should not time out (or at least I should be able to configure a really long timeout, taking comfort in the fact that the loss of the last "active" stub will cause the instance to be automatically removed before the timeout).
Do any containers actually implement the SFSB lifecycle in this way so as to avoid the "remove" method?