0

I have an Java EE application as follows:
- Server is on Amazon (large instance, 2 CPU @ 2.27GHz, 8GB RAM) - Static content served directly by Apache
- JSF2 (Mojarra 2.1.3) and JPA 2 (Eclipselink 2.3.0) running on Glassfish 3.1.1
- Facelets/XHTML get content from ViewScoped managed beans, that connect to @Local Stateless EJB that do all the processing, including getting data from other @Local Stateless EJB that use JPA
So typically:

XHTML --> ViewScoped Managed Bean --> Service EJB --> Data EJB --> JPA

I know I could/should remove the 2 layers of EJB to one or even none, given I run only one instance of Glassfish but for now I don't think this is the issue.

The performance of the application is ok (2.2MB including images in < 5s). The problem is that when we have > 90 users online the system becomes really slow ( > 30 s per page, even if most of it is cached).
At that time the CPU was 50% used and RAM was 100% used.

So I ran JProfiler and I am not sure how to deal with one type of result.
In the homepage, we have a list of categories, and a number of product is associated to each category (a shopping website that tells how many product in each category). The code to get the list of Category is:

ViewScoped Bean

public List<Category> getLiveCategoriesInfo() {
    if (liveCategories == null) {
        liveCategories = liveCategoryService.getLiveCategories(getLocale().getLang().getLanguageId());
    }
    return liveCategories;
}

getLocale() is retrieved from a SessionScoped Bean injected using ManagedProperty

Service EJB:

public List<Category> getLiveCategories(final Integer langId) {
  List<LiveCategory> lives = categoryBean.getLiveCategories(langId);
  // ... some processing involving looping through the list above
  return livesCategories;
}

Data EJB:

public List<LiveCategory> getLiveCategories(final Integer langId) {
  List<LiveCategory> categories = new ArrayList<LiveCategory>();
  Query cq = getEntityManager().createNamedQuery(Category.FIND_LIVE);
  try {
    categories = cq.getResultList();
  } catch (NullPointerException npe) {
     // ...
  }
  return categories;
}

JProfiler Memory View shows that at every request on the homepage (even for the same user) a new batch of Category is added to the memory (43 to be precise, which is the number of categories displayed). The Category is not managed by JPA (the list from JPA is used to create POJO 'manually').
How can I release these entities from the memory. I would expect them to be GC when the view is gone. But the ViewScoped bean is itself is not GC'd, there is a bunch of instances that stay in memory.

What should I look for to release these objects?
- Is using a @ManagedProperty in a ViewScoped bean to get an instance of SessionScoped bean preventing the ViewScoped one to be GC'd?
- Is there some other mistake I should look for?

I did check the other threads about JSF Best practices and Performance guidelines but it doesn't help.

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
JScoobyCed
  • 10,203
  • 6
  • 34
  • 58

2 Answers2

0

May be you can try to release the FacesContext when the user logs out.

srivenky
  • 456
  • 2
  • 3
0

I think your problem is related to how you are using view scope and session scope. In few words, you are filling the memory with objects that does not change over the lifetime of the page. Instead, you should use a request scope bean to cache those results only while the request is processed, and use @ManagedProperty annotation or whatever(create value expression or call Application.evaluateExpressionGet to get the parameters from your view scope or session scope beans. In that way, the reference to the entities will be released when the request ends, and they will be collected by the GC.

If you are really interested in the performance part, check this blog:

Understanding JSF 2 and Wicket: Performance Comparison

The test code is already tuned for get the best performance for JSF and Wicket. It is quite simple to tune JSF, so you usually should watch your ORM tool for performance tips.

lu4242
  • 2,318
  • 1
  • 15
  • 15
  • I did some longer tests with the profiler and I can see that the ViewScoped beans are GC'd but less often. I changed one to RequestScoped (it actually made sense since it is read only stuff and it needs to get fresh data from DB at each request) and it was collected more often. I turned my optimizations to DB SQLs and could reduce by 30% the nb of DB queries which is good enough for now – JScoobyCed May 23 '12 at 03:07