servlet 规范没有说明任何有关内存考虑的内容,因此您不会得到任何帮助。
除非特别配置,否则 Tomcat 将允许您使用 HttpSession 对象(实际上是它们的内容)用尽所有可用内存,最终 JVM 将开始抛出OutOfMemoryError
s,可能会使您的服务器停机(尽管 JVM 将继续运行,许多事情都会表现得......不可预测且不幸的是)。
如果单个请求开始在局部变量等中使用大量内存,则请求处理线程将受到影响OutOfMemoryError
并停止处理当前请求。(我相信在这种情况下,请求处理线程实际上会被Tomcat请求处理线程池回收)。垃圾收集器可能会在此后不久运行并重新声明该请求使用的内存,并且您的服务器将稳定下来。
另一方面,如果你用完大量内存并将这些对象存储到用户的 sHttpSession
中,那么 GC 将无法释放任何内存,并且您的服务器将不断遭受OutOfMemoryError
s 的影响。虽然 Tomcat 会在指定的时间表上过期会话(默认是在 30 分钟不活动之后),但会话清理线程可能会遇到一个OutOfMemoryError
during operation 并因此无法执行其职责,从而使整个情况更加复杂(因为实际上,HttpSession
s 永远不会到期)。
有几种方法可以缓解上述不幸的情况。哪一个对您有意义取决于您的要求和环境。
增加堆大小。这显然只会让你到目前为止。如果您正在用相关对象填充 16GiB 堆HttpSession
,那么您将达到商品硬件的极限,您不能简单地购买更大的盒子。
减少会话过期时间(默认为 30 分钟)。如果会话没有显式终止(例如,通过注销功能),则HttpSession
对象及其所有内容会一直存在,直到过期间隔过去。如果您在大量废弃会话中拥有大量数据,则减少会话到期时间可能会给您一些喘息的空间。
停止将这么多数据放入用户的HttpSession
. 虽然这似乎是一个令人讨厌的建议(“停止这样做”),但它确实是一个有效的建议:你真的需要在会话本身中存储这么多东西吗?使用某种数据存储(关系数据库、非关系数据库如 Cassandra、webcache 等)怎么样?也许将数据存储在磁盘上的文件中?虽然这些建议肯定会限制您快速访问数据的能力,但它们肯定是比让您的服务器在会话中大量内容的重压下崩溃更好的选择。
使用 Tomcat 的PersistentManager
,它是一个会话管理器,能够将活动(但空闲)会话交换到某些外部存储(默认情况下可以使用基于文件和基于 JDBC 的存储机制)。当您找到其他地方将您推送的所有数据放入用户会话时,这可以让您走得很远。
除了 #4 之外的所有内容都适用于任何 servlet 容器。#4 应该对 JBoss 用户可用,因为 JBoss 在内部使用 Tomcat。对于其他容器,您可能会发现存在类似的功能。