JSF Enterprise应用程序内存使用情况

时间:2012-05-22 08:15:43

标签: jsf-2 memory-leaks jprofiler

我有一个Java EE应用程序如下:
- 服务器在亚马逊(大型实例,2 CPU @ 2.27GHz,8GB RAM) - Apache直接提供的静态内容 - 在Glassfish 3.1.1上运行的JSF2(Mojarra 2.1.3)和JPA 2(Eclipselink 2.3.0)
- Facelets / XHTML从ViewScoped托管bean获取内容,这些bean连接到执行所有处理的@Local Stateless EJB,包括从使用JPA的其他@Local Stateless EJB获取数据 通常如此:

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

我知道我可以/应该删除2层EJB到一个甚至没有,因为我只运行了一个Glassfish实例,但是现在我认为这不是问题。

应用程序的性能还可以(2.2MB包括< 5s中的图像)。问题是,当我们有>在线的90个用户系统变得非常慢(每页大约30秒,即使大部分是高速缓存的) 那时CPU使用率为50%,RAM使用率为100%。

所以我跑了JProfiler,我不知道如何处理一种结果。
在主页中,我们有一个类别列表,并且每个类别都有一些产品(一个购物网站,告诉每个类别有多少产品)。获取类别列表的代码是:

ViewScoped Bean

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

注入的SessionScoped Bean中检索

getLocale()

服务EJB:

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

数据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内存视图显示,在主页上的每个请求(即使是同一个用户)中,新的一批类别被添加到内存中(准确地说是43,这是显示的类别数)。类别不由JPA管理(JPA中的列表用于手动创建POJO) 如何从内存中释放这些实体。当视图消失时,我希望它们是GC。但ViewScoped bean本身不是GC'd,有一堆实例留在内存中。

我应该寻找什么来释放这些物品?
- 在ViewScoped bean中使用@ManagedProperty来获取SessionScoped bean的实例,防止ViewScoped bean被GC化吗? - 我应该寻找其他的错误吗?

我确实检查了有关JSF最佳实践和性能指南的其他主题,但它没有帮助。

2 个答案:

答案 0 :(得分:0)

可能是您可以尝试在用户注销时释放FacesContext。

答案 1 :(得分:0)

我认为您的问题与您使用视图范围和会话范围的方式有关。简而言之,您正在使用在页面生命周期内不会更改的对象填充内存。相反,您应该使用请求范围bean仅在处理请求时缓存这些结果,并使用@ManagedProperty注释或其他任何内容(创建值表达式或调用Application.evaluateExpressionGet来从视图范围或会话范围bean中获取参数通过这种方式,当请求结束时,将释放对实体的引用,并且GC将收集它们。

如果您对性能部分真的感兴趣,请查看此博客:

Understanding JSF 2 and Wicket: Performance Comparison

测试代码已经过调整,以获得JSF和Wicket的最佳性能。调整JSF非常简单,因此您通常应该观察ORM工具以获得性能提示。