今天出现了一个问题:
想象一下,我有很多并发用户访问我的网站,每个用户都有自己的数据存储在用户会话中。考虑到我的JVM中可用的内存有限,当并发活动会话到达容器JVM内存不足的时候会发生什么或者应该发生什么?
我试图在servlet规范中找到关于应该发生什么的内容,但是那里没有任何确定性,它只是说开发人员可以访问会话对象等。这让我认为它必须是提供者特定的。
以Tomcat为例,网络服务器是否刚开始投掷OutOfMemoryException
?或者它处理这个问题的方式更聪明,例如将会话分配到另一个缓存?还是另一种方式?
答案 0 :(得分:4)
servlet规范没有提及任何有关内存注意事项的内容,因此您将无法获得帮助。
除非专门配置,否则Tomcat将允许您使用HttpSession对象(实际上,它们的内容)使用所有可用内存,最终JVM将开始抛出OutOfMemoryError
,可能会导致服务器停机(虽然JVM将继续运行,很多事情会表现得......不可预测且不幸)。
如果单个请求在本地变量等中使用大量内存,则请求处理线程将遇到OutOfMemoryError
并停止处理当前请求。 (我相信在这种情况下,请求处理线程实际上将由Tomcat请求处理线程池回收)。垃圾收集器很可能在此后不久运行并重新声明该请求使用的内存,您的服务器将稳定下来。
另一方面,如果您占用大量内存并将这些对象存储到用户的HttpSession
中,那么GC无法释放任何内存,您的服务器将不断受到OutOfMemoryError
s的影响。虽然Tomcat将按指定的时间表到期(默认是在30分钟不活动后),但会话清理线程在操作期间可能会遇到OutOfMemoryError
,因此无法履行其职责,使整个情况更加复杂(因为,实际上,HttpSession
将永不过期。
有几种方法可以缓解上述不幸情况。哪一个对你有意义取决于你的要求和环境。
增加堆大小。这显然只会让你到目前为止。如果您使用HttpSession
和相关对象填充16GiB堆,那么您将达到商品硬件的极限,而不能简单地购买更大的盒子。
缩短会话到期时间(默认为30分钟)。如果未明确终止会话(例如,通过注销功能),则HttpSession
对象及其所有内容将一直存在,直到过期时间间隔过去。如果您在很多被遗弃的会话中有大量数据,减少会话到期时间可能会给您一些喘息的空间。
停止将大量数据放入用户的HttpSession
。虽然这看起来像是一个令人讨厌的建议(“停止这样做”),但老实说这是一个有效的建议:你真的需要在会话中存储这么多东西吗?如何使用某种数据存储(关系数据库,非关系型数据库,如Cassandra,webcache等)?也许将数据存储在磁盘上的文件中?虽然这些建议肯定会限制您快速访问 数据的能力,但它们肯定是比您的服务器在会话中如此多的重量下崩溃更好的选择。
使用Tomcat的PersistentManager
,它是一个会话管理器,能够将活动(但空闲)会话交换到某些外部存储(默认情况下,基于文件和基于JDBC的存储机制可用)。这可以帮助你找到一些其他的地方,把你所有的数据放到用户的会话中。
#4以外的所有内容都适用于任何servlet容器。 #4应该可供JBoss用户使用,因为JBoss在内部使用Tomcat。对于其他容器,您可能会发现存在类似的功能。
答案 1 :(得分:0)
通常这取决于供应商。但是,容器可以自行决定将会话序列化到磁盘(,如果会话数据可以序列化)。
如果容器可以执行此操作,它可以在需要时推出非活动会话,并在需要时再次恢复它们,更好地使用内存,从而推迟任何OutOfMemoryExceptions。