0

我有一个 Java EE 应用程序,如下所示:
- 服务器在 Amazon 上(大型实例,2 CPU @ 2.27GHz,8GB RAM) - 由 Apache 直接提供的静态内容
- JSF2 (Mojarra 2.1.3) 和 JPA 2 (Eclipselink 2.3.0 ) 在 Glassfish 3.1.1 上运行
- 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,包括 < 5 秒内的图像)。问题是当我们有 > 90 个用户在线时,系统变得非常慢(每页 > 30 秒,即使其中大部分被缓存)。
那时 CPU 使用了 50%,RAM 使用了 100%。

所以我运行了 JProfiler,但我不确定如何处理一种类型的结果。
在主页中,我们有一个类别列表,并且每个类别关联了许多产品(一个告诉每个类别中有多少产品的购物网站)。获取类别列表的代码是:

ViewScoped Bean

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

getLocale()从使用 ManagedProperty 注入的 SessionScoped Bean 中检索

服务 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 Memory View 显示,在主页上的每个请求(即使对于同一个用户),都会将新一批 Category 添加到内存中(准确地说是 43,这是显示的类别数)。类别不由 JPA 管理(来自 JPA 的列表用于“手动”创建 POJO)。
我怎样才能从内存中释放这些实体。当视图消失时,我希望它们成为 GC。但是 ViewScoped bean 本身不是 GC'd,有一堆实例留在内存中。

我应该寻找什么来释放这些对象?
- 是否@ManagedProperty在 ViewScoped bean 中使用 a 来获取 SessionScoped bean 的实例,从而阻止 ViewScoped 被 GC?
- 我应该寻找其他错误吗?

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

4

2 回答 2

0

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

于 2012-05-22T09:13:45.630 回答
0

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

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

了解 JSF 2 和 Wicket:性能比较

测试代码已经为获得 JSF 和 Wicket 的最佳性能进行了调整。调整 JSF 非常简单,因此您通常应该关注您的 ORM 工具以获取性能提示。

于 2012-05-22T09:20:34.713 回答