【发布时间】:2015-11-04 18:05:16
【问题描述】:
每个会话的内存增长
我们在使用 JSF 2.2 (2.2.12) 和 Mojarra 时遇到了高内存消耗。在调查了我们的负载测试后,我们发现我们的 ViewScoped Bean 中的数据量非常大(有时超过 1MB)。无论如何 - 当从一个视图导航到另一个视图时,会话内存大小会越来越大。我们不能在短期内减小 bean 的大小,所以这种行为会产生相当大的影响。
解决方案 1 - 更改上下文参数(不起作用)
现在 - 我们使用 Mojarra 的官方上下文参数,默认设置为 15:
com.sun.faces.numberOfLogicalViews
com.sun.faces.numberOfViewsInSession
将这些参数更改为较低的值不会对负载测试中的内存消耗产生任何影响。
解决方案 2 - 更改 activeViewMapsSize(工作)
我们在调试 Mojarra 时,在ViewScopeManager 中发现了以下代码:
Integer size = (Integer) sessionMap.get(ACTIVE_VIEW_MAPS_SIZE);
if (size == null) {
size = 25;
}
保留上次访问的视图的默认大小似乎是 25。看到这一点,我们实现了一个会话监听器,将这个值设置为 1:
public class SetActiveViewMapsSizeSessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent event) {
event.getSession().setAttribute(ViewScopeManager.ACTIVE_VIEW_MAPS_SIZE, 1);
}
}
这显然奏效了。由于只保留了 1 个视图,因此内存停止增长。
那么为什么内存中有 25 个视图?
所以 Mojarra 会在内存中保留 25 个视图的历史记录,以防 Session 中没有定义不同的值。我找不到任何关于此的文档。有人可以解释这是为了什么吗?是为了浏览器返回吗?我们在 JSF 页面上禁用了缓存。所以浏览器返回总是会创建一个新的视图。这对我们来说应该不是问题。
解决方案 2 是否有效?有人可以解释这种方法的缺点吗?
更新 1
经过各种cmet和更深的调试,结果是:
-
com.sun.faces.numberOfLogicalViews定义了logicalViewMap的大小,它只存储(!)ui组件树的状态 -
com.sun.faces.application.view.activeViewMapsSize定义了包含 ViewScoped bean 的 activeViewMap 的大小
将 numberOfLogicalViews 更改为 1 时,mojarra 仍将跟踪最近 25 个视图的所有视图范围 bean。当您以相反的方式配置它时 - numberOfLogicalViews 到 15 和 activeViewMapsSize 到 1 - 我猜由于缺少数据,视图无法正确初始化。我们甚至没有例外。我想了解,为什么 mojarra 选择将 activeViewMapsSize 设置为高于 numberOfLogicalViews 并且不一样,因为我们希望调整内存消耗而不出现不可预测的行为。
更新 2
我们在 Mojarra 创建了一个问题:JAVASERVERFACES-4015。
【问题讨论】:
-
我的意思是如果你在上下文中设置 ACTIVE_VIEW_MAPS_SIZE (使用正确的字符串)。你试过了吗?
-
我在会话映射中设置了它,它起作用了(解决方案 2)。没有像
com.sun.faces.application.view.activeViewMapsSize这样的 WebContextInitParameter(ACTIVE_VIEW_MAPS_SIZE 后面的值)。我想知道的是值 25!为什么这么多。 -
这是一个疏忽。很尴尬的一个。应该是
numberOfLogicalViews。周围的工作是一个很好的。另一种方法是切换到 OmniFaces@ViewScoped,它确实尊重numberOfLogicalViews。 -
它在技术上应该与
numberOfLogicalViews * numberOfViewsInSession相同,但numberOfViewsInSession现在很少有用了。至少,每个视图状态都应该附加一个视图范围 bean,并且当关联的视图状态被删除时,不应该有悬空的视图范围 bean。 -
回到这个问题,从 OmniFaces 2.2 开始,它的
@ViewScoped将在页面卸载后立即销毁,因此不再不必要地停留在会话中。