当前位置: 首页 > 知识库问答 >
问题:

JSF 2.2内存消耗:为什么Mojarra将最近25个视图的ViewScoped Bean保留在内存中?

曾晨
2023-03-14

每个会话的内存增长

使用JSF2.2 (2.2.12)和Mojarra,我们遇到了高内存消耗。在调查了我们的负载测试后,发现我们的ViewScoped Beans中的数据大小相当高(有时超过1MB)。无论如何——当从一个视图导航到另一个视图时,会话内存大小会不断增长。我们不能在短期内减少bean的大小,因此这种行为会产生相当大的影响。

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

现在,我们使用了Mojarra的官方上下文参数,默认设置为15:

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

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

解决方案2-更改activeViewMapsSize(工作)

我们正在调试Mojara,并在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);
    }
}

这显然奏效了。内存停止增长,因为只保留了一个视图。

那么为什么内存中有25个视图呢?

所以Mojarra在内存中保存了25个视图的历史记录,以防会话中定义了不同的值。我找不到任何关于这个的文件。有人能解释一下这是干什么用的吗?是回浏览器的吗?我们在JSF页面上禁用了缓存。所以浏览器后退总是会创建一个新视图。这不应该是我们的问题。

解决方案2是有效的方法吗?有人能解释一下这种方法的缺点吗?

更新1

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

  • com。太阳面孔。NumberOfLogicalView定义logicalViewMap大小,它只存储(!)ui组件树的状态

numberOfLogicalViews更改为1时,mojarra仍将跟踪最后25个视图的所有视图范围bean。当您以另一种方式配置它时-numberOfLogicalViews为15和activeViewMapsSize为1-我猜由于缺少数据,视图无法正确初始化。我们甚至没有例外。我想理解,为什么mojarra选择将activeViewMapsSize设置为高于numberOfLogicalViews的值,而不是相同的值,因为我们希望调整内存消耗,而不会出现不可预测的行为。

更新2

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


共有1个答案

刘泰
2023-03-14

为什么Mojarra会在内存中保留最后25个视图的ViewScope bean?

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

无论如何,当从一个视图导航到另一个视图时,会话内存大小会不断增长。

如果您在同一个浏览器选项卡中从一个视图导航到另一个视图,这确实毫无意义。但在新浏览器选项卡中打开下一个视图时,这是有意义的。这样,当您切换回上一个浏览器选项卡并继续与那里的视图交互时,上一个浏览器选项卡中的视图仍能正常工作。

我们不能在短期内减少豆子的大小,所以这种行为有相当大的影响。

从技术上讲,可以在客户端检测当前页面是否已卸载,并将此情况通知服务器。现在,可以使用pagehide事件来检查当前视图是否已在客户端和导航器中被破坏。sendBeacon可用于以可靠的方式将此情况通知服务器(例如使用unloadXMLHttpRequest的组合不太可靠,因为无法保证它是否会按时击中服务器)。

自OmniFaces 2.2版(2015年11月)以来,所有这些都是在OmniFaces@ViewScoped背后的逻辑中实现的,并在OmniFaces 2.7.3版(2019年11月)之后的几年中形成了目前的形态。如果您已经在使用CDI来管理bean,那么就应该换出import javax。面孔。看法视域 行,由import org导入。无所不在。cdi。视域 以利用此功能。在我参与的一个项目中,自从本机JSF视图范围bean迁移到OmniFaces视图范围bean以来,内存使用量减少了70%。

  • com.sun.faces.numberOfViewsIn会话vscom.sun.faces.numberOfLogicalViews
  • 如何检测和删除(在会话期间)无法垃圾收集的未使用@ViewScoped bean
  • JSF:Mojarra vs. OmniFaces@ViewScoped:@PreDestroy调用但bean不能被垃圾收集

 类似资料:
  • 我们的软件正在通过一个从内存流读取数据的GZipStream解压某些字节数据。这些数据以4KB的块解压缩,并写入另一个内存流。 我们已经意识到进程分配的内存远高于实际解压的数据。 示例:具有2425536字节的压缩字节数组被解压缩为23050718字节。我们使用的内存分析器显示了方法MemoryStream。设置容量(Int32值)分配的67104936字节。这是保留内存和实际写入内存之间的2.9

  • 我听说chrome已经为“img”元素实现了本机延迟加载,firefox也将很快跟进。 我找到的解释告诉我们,当您向img元素添加一个属性load=“lazy”时,它只会在浏览器认为它“靠近”视口时请求src url,“close”的定义取决于实际可用带宽。 我的问题实际上是关于内存消耗。在实际加载了延迟加载的图像,并且图像离视口足够远之后,浏览器是否会释放内存,在必要时再次延迟加载(可能是从磁盘

  • 问题内容: 我需要监视应用程序产生的线程消耗的内存量。如果贪婪的线程消耗太多内存,则想法是采取纠正措施。我已提到Java线程占用多少内存?。关于该链接的建议之一是在我尝试以下工作时使用。 我在四个线程上运行了很长时间。尽管作业不会连续地累积内存,但是所返回的值会不断增加,甚至不会下降。这意味着不会返回线程使用的堆上的实际内存量。它返回自线程启动以来在堆上为线程分配的内存总量。我的平台详细信息如下:

  • 我需要监控应用程序生成的线程所消耗的内存量。如果贪婪的线程占用了太多内存,那么我们可以采取纠正措施。我提到了我的java线程需要多少内存?。关于该链接的建议之一是在ThreadMXBean中使用getThreadAllocatedBytes 我用以下作业试验了getThreadAllocatedBytes。 我在四个线程上运行了相当长的时间。虽然作业不会连续累积内存,但getThreadAlloc

  • 不是内存泄漏或类似的问题,因为第一次连接后内存使用量不会增加,所以优化可能是加载更少的模块或做一些不同的事情...

  • 用户上传一个由一百万字组成的巨大文件。我解析文件并将文件的每一行放入< code>LinkedHashMap中 我需要按键访问和删除O(1)。此外,我需要保留访问顺序,从任何位置迭代并排序。 内存消耗是巨大的。我启用了的重复数据删除功能,该功能出现在Java 8中,但事实证明,消耗了大部分内存。 我找到了< code>LinkedHashMap。Entry占用40个字节,但是只有2个指针——一个指