[jboss-user] [JBoss Seam] - Memory leak in SFSB in session scope in Seam 2.0.0 on JBoss

susnet do-not-reply at jboss.com
Tue Dec 25 21:48:59 EST 2007


Hi!
I upgraded to Seam 2.0.0.GA and it is running on JBoss 4.2.2.

I have a SFSB in Session scope. The SFSB has an ObjectPool, which is really just a Collection of Entities. The entities in the collection are of type TeaserRecipe which just maps to a table in my database.
For each httpRequest for certain pages the method  getNextTeaserRecipes() are called. This is configured in pages.xml.

Now to the strange behaviour. If I just use the default settings for conversation timeout and session timeout OR if i set it to for example:
conversation timeout = 600000  ( = 10 minutes)
session timeout = 10
Then the number of instances of TeaserRecipe just grows and gradually leads to OutOfMemoryException. I have also tested a lot of other configurations where session timeout is much longer than conversation timeout and vice versa, all with the same result -> Growing number or instances and OutOfMemoryException if I just wait long enough before restarting JBoss.

But if don't set any conversation timeout at all AND set session timeout to 2 minutes it works fine and the instances don't grow and gets garbage collected as they should.

Any Ideas???? 



My SFSB. It has 4 objectPools in reality, but i stripped it to one to save some space and making it easier to read.

  | import java.util.*;
  | import javax.ejb.Remove;
  | import javax.ejb.Stateful;
  | import javax.ejb.Stateless;
  | import javax.persistence.*;
  | import org.jboss.seam.ScopeType;
  | import org.jboss.seam.annotations.*;
  | import org.jboss.seam.log.Log;
  | import recepten.common.ObjectPool;
  | import recepten.entities.db.TeaserRecipe;
  | 
  | @Stateful
  | @Name("recipeTeaserService")
  | @Scope(ScopeType.SESSION)
  | public class RecipeTeaserServiceBean implements
  | 		recepten.actions.RecipeTeaserServiceLocal {
  | 
  | 	@Logger Log log;
  | 
  | 	@PersistenceContext(type = PersistenceContextType.EXTENDED)
  | 	private EntityManager em;
  | 	
  | 	ObjectPool<TeaserRecipe> recipePoolSidebarLeft1;
  | 	
  | 	private TeaserRecipe recipeSidebarLeft1;	
  | 		
  | 	public RecipeTeaserServiceBean() {
  | 	}
  | 
  | 	@Create
  | 	public void initPools() {
  | 		// Create new objectPools
  | 		recipePoolSidebarLeft1 = new ObjectPool<TeaserRecipe>();
  | 		
  | 		// Create a pool of the pools
  | 		ArrayList<ObjectPool<TeaserRecipe>> poolList = new ArrayList<ObjectPool<TeaserRecipe>>();
  | 		poolList.add(recipePoolSidebarLeft1);		
  | 
  | 		// Get recipes from database
  | 		List<TeaserRecipe> teaserRecipeList = em
  | 				.createQuery(
  | 						"SELECT t FROM TeaserRecipe t WHERE t.show = true ORDER BY seq")
  | 				.getResultList();
  | 
  | 		int poolListIndex = 0;
  | 		for (TeaserRecipe teaserRecipe : teaserRecipeList) {
  | 			poolList.get(poolListIndex).add(teaserRecipe);
  | 			if (++poolListIndex == poolList.size()) {
  | 				poolListIndex = 0;
  | 			}
  | 		}
  | 	}
  | 	
  | 	public TeaserRecipe getRecipeSidebarLeft1() {		
  | 		return recipeSidebarLeft1;
  | 	}
  | 	
  | 		
  | 	public void getNextTeaserRecipes() {
  | 		// Get next recipe from pool		
  | 		recipeSidebarLeft1 = recipePoolSidebarLeft1.next();		
  | 	}
  | 
  | 	@Destroy
  | 	@Remove
  | 	public void destroy() {		
  | 	}
  | 

ObjectPool:

  | package recepten.common;
  | 
  | import java.util.ArrayList;
  | import java.util.Collections;
  | 
  | public class ObjectPool<T> {
  |     
  |     ArrayList<T> list = new ArrayList<T>();
  |     int pointer;
  |     
  |     public ObjectPool() {}
  |     
  |     public void add(T instance) {
  |       list.add (instance);
  |     }
  |     
  |     public T next(){
  |         if (++pointer == list.size()) {
  |             pointer = 0;
  |         }
  | 	if (list.size () == 0) {
  | 	  return null;
  | 	}
  |         return list.get(pointer);
  |     }
  |     
  |     public void shuffle() {
  |       Collections.shuffle (list);
  |     }
  | }
  | 

TeaserRecipe:

  | @Entity
  | @Table(name = "teaserrecipe")
  | public class TeaserRecipe implements Serializable {
  | 
  | 	@Id
  | 	@Column(name = "recipeid", nullable = false)
  | 	private Integer recipeid;
  | 
  | 	@Column(name = "headline")
  | 	private String headline;
  | 
  | 	@Column(name = "teasertext")
  | 	private String teasertext;
  | 
  | 	@Column(name = "seq", nullable = false)
  | 	private int seq;
  | 
  | 	@Column(name = "show", nullable = false)
  | 	private boolean show;
  | 
  | 	@JoinColumn(name = "recipeid", referencedColumnName = "recipeid", insertable = false, updatable = false)
  | 	@OneToOne
  | 	private Recipe recipe;
  |   
  |   /** Creates a new instance of TeaserRecipe */
  |   public TeaserRecipe () {
  |   }
  | 
  |   // Getters and setters and overridden equals, toString and hashcode methods.
  | }
  | 

pages.xml (only the interesting part)

  | <page view-id="/pages/*">   
  |     <action execute="#{recipeTeaserService.getNextTeaserRecipes}"/>    
  |   </page>
  | 


The same code worked fine in Seam 1.2.1. and JBoss 4.0.5. 

Please tell me if there are some more code you would like to see.

Any help is appreciated since now I'm forced to have a session timeout set to 2 minutes which leads to many View experiation exceptions since the timeout is too short. 

Thanks in advance!

View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4115434#4115434

Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4115434



More information about the jboss-user mailing list