JSF 2.2内存消耗:为什么Mojarra为什么将最近25个视图的ViewScoped Bean保留在内存中? [英] JSF 2.2 Memory Consumption: Why does Mojarra keep the ViewScoped Beans of the last 25 Views in Memory?

查看:91
本文介绍了JSF 2.2内存消耗:为什么Mojarra为什么将最近25个视图的ViewScoped Bean保留在内存中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

每个会话的内存增加

使用Mojarra的JSF 2.2(2.2.12),我们正在经历大量内存消耗.在调查了我们的负载测试之后,事实证明我们的ViewScoped Bean中的数据量非常大(有时超过1MB).无论如何-从一个视图浏览到另一个视图时,会话内存大小会越来越大.我们不能在短期内减小bean的大小,因此这种行为会产生一定的影响.

We are experiencing high memory consumption using JSF 2.2 (2.2.12) with Mojarra. After investigating our load tests, it turned out that the size of data in our ViewScoped Beans is quite high (sometimes more than 1MB). Anyway - when navigating from view to view, the session memory size grows and grows. We can't decrease the size of the beans on short-term, so this behavior has quite some impact.

解决方案1-更改上下文参数(不起作用)

现在-我们在Mojarra中使用了官方的context参数,默认情况下将其设置为15:

Now - we played around with the official context parameter from Mojarra which are set to 15 by default:

com.sun.faces.numberOfLogicalViews
com.sun.faces.numberOfViewsInSession

将这些参数更改为较低的值不会对我们的负载测试中的内存消耗产生任何影响.

Changing those parameters to a lower value did not have any impact on the memory consumption in our load tests.

解决方案2-更改activeViewMapsSize(有效)

我们正在调试Mojarra,并在ViewScopeManager中找到了以下代码:

We were debugging Mojarra and found the following Code in ViewScopeManager:

Integer size = (Integer) sessionMap.get(ACTIVE_VIEW_MAPS_SIZE);
if (size == null) {
    size = 25;
}

用于保留上一次访问的视图的默认大小似乎是25.看到这一点,我们实现了一个Session Listener,它将该值设置为1:

The default size for keeping the last visited views seems to be 25. Seeing this, we implemented a Session Listener which sets this value to 1:

public class SetActiveViewMapsSizeSessionListener implements HttpSessionListener {
    @Override
    public void sessionCreated(HttpSessionEvent event) {
        event.getSession().setAttribute(ViewScopeManager.ACTIVE_VIEW_MAPS_SIZE, 1);
    }
}

那显然行得通.由于仅保留了1个视图,因此内存停止增长.

That obviously worked. The memory stopped growing since only 1 view is kept.

那为什么要在内存中查看25个视图?

因此,如果在Session中没有定义其他值,Mojarra将在内存中保留25个视图的历史记录.我找不到与此有关的任何文档.有人可以解释这是干什么的吗?是否用于浏览器返回?我们在JSF页面上禁用了缓存.因此,浏览器后退将始终创建一个新视图.对我们来说这不应该是一个问题.

So Mojarra keeps a history of 25 Views in Memory in case of not a different value is defined in Session. I can't find any documentation about this. Can someone explain what this is for? Is it for Browser Back? We have caching disabled on our JSF pages. So browser back will always create a new view. This shouldn't be an issue for us.

解决方案2是否有效?有人可以解释这种方法的弊端吗?

Is Solution 2 a valid approach? Could someone explain the drawbacks of this approach?

更新1

经过各种评论和更深入的调试,结果表明:

After various comments and a deeper debugging, it turned out that:

  • com.sun.faces.numberOfLogicalViews定义了logicalViewMap的大小,该大小仅存储(!)ui组件树的状态
  • com.sun.faces.application.view.activeViewMapsSize定义了ActiveViewMap的大小,该大小包含ViewScoped bean
  • com.sun.faces.numberOfLogicalViews defines the logicalViewMap size, which stores only(!) the state of the ui component tree
  • com.sun.faces.application.view.activeViewMapsSize defines the size of the activeViewMap, which holds the ViewScoped beans

numberOfLogicalViews更改为1时,mojarra仍会跟踪最近25个视图中所有视图作用域的bean.当您以相反的方式配置它-numberOfLogicalViews到15和activeViewMapsSize到1时,由于我想丢失了数据,因此无法正确初始化视图.我们甚至都没有例外.我想了解一下,为什么mojarra选择将activeViewMapsSize设置为高于numberOfLogicalViews而不是相同,因为我们想调整内存消耗而不会出现无法预测的行为.

When changing numberOfLogicalViews to 1, mojarra will still keep track of all view scoped beans of the last 25 views. When you configure it the other way around - numberOfLogicalViews to 15 and activeViewMapsSize to 1 - the view cannot be correctly initialized due to missing data I guess. We didn't even get an exception. I would like to understand, why mojarra chose to set the activeViewMapsSize higher than the numberOfLogicalViews and not the same since we want to tune our memory consumption without getting an unpredictable behavior.

更新2

我们在Mojarra创建了一个问题: JAVASERVERFACES-4015 .

We created an issue at Mojarra: JAVASERVERFACES-4015.

推荐答案

为什么Mojarra会在内存中保留最近25个视图的ViewScoped Bean?

因为也可以在新的浏览器选项卡中而不是当前浏览器选项卡中打开网页.不幸的是,没有基于普通的HTTP GET请求来确定是在现有浏览器选项卡中还是在新浏览器选项卡中打开视图的防弹方法.因此,无论是否在同一浏览器选项卡中打开网页,所有关联的bean都保留在内存中.

Because a web page can also be opened in a new browser tab rather than the current browser tab. There is unfortunately no bulletproof way to determine based on a plain vanilla HTTP GET request whether a view is being opened in an existing browser tab or in a new browser tab. Hence all the associated beans are kept in memory regardless of whether the web page is opened in the same browser tab or not.

无论如何-从一个视图导航到另一个视图时,会话内存大小会越来越大.

如果您在同一浏览器选项卡中从一个视图浏览到另一个视图,这的确没有任何意义.但是,当您在新的浏览器选项卡中打开下一个视图时,这确实有意义.这样,当您切换回上一个浏览器选项卡并继续与该视图中的视图进行交互时,上一个浏览器选项卡中的视图可以正常工作.

This makes indeed no sense if you navigate from view to view within the same browser tab. But this does make sense when you open the next view in a new browser tab. This way the view in previous browser tab keeps working fine when you switch back to the previous browser tab and continue interacting with the view over there.

短期内我们无法减小bean的大小,因此这种行为会产生一定的影响.

从技术上讲,可以在客户端检测当前页面是否已卸载并将此情况通知服务器.如今, pagehide 事件可以是用于检查当前视图是否已在客户端被销毁,并且

It's technically possible to detect in the client side whether the current page has been unloaded or not and notify the server about this condition. These days, the pagehide event can be used to check whether the current view has been destroyed in the client side, and the navigator.sendBeacon can be used to notify the server about this condition in a reliable way (using the combination of e.g. unload and XMLHttpRequest is less reliable as there is no guarantee whether it will actually hit the server on time).

从OmniFaces 2.2(十一月)以来,所有这些都是在 OmniFaces @ViewScoped 背后的逻辑中实现的自从OmniFaces 2.7.3(2019年11月)起,在过去的几年中逐渐形成了目前的形态.如果您已经在使用CDI来管理Bean,那么应该使用import org.omnifaces.cdi.ViewScoped;换出源代码中的import javax.faces.view.ViewScoped;行,以便利用它.在我参与的一个项目中,自从将本地JSF视图作用域的bean迁移到OmniFaces视图作用域的bean以来,内存使用减少了70%.

This all is implemented in the logic behind OmniFaces @ViewScoped since OmniFaces 2.2 (November 2015) and across years crystallized into its current shape since OmniFaces 2.7.3 (November 2019). If you're already using CDI to manage beans, then it should be a matter of swapping out import javax.faces.view.ViewScoped; lines in your source code by import org.omnifaces.cdi.ViewScoped; in order to utilize this. In one project I've worked with, the memory usage has decreased with 70% since the migration of native JSF view scoped beans to OmniFaces view scoped beans.

  • com.sun.faces.numberOfViewsInSession vs com.sun.faces.numberOfLogicalViews
  • How detect and remove (during a session) unused @ViewScoped beans that can't be garbage collected
  • JSF: Mojarra vs. OmniFaces @ViewScoped: @PreDestroy called but bean can't be garbage collected

这篇关于JSF 2.2内存消耗:为什么Mojarra为什么将最近25个视图的ViewScoped Bean保留在内存中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆