我正在尝试在我们的Tomcat Java Web应用程序中发生内存泄漏,并且认为我在向其中一个JSP发出重复请求时发现了它。然而,在将其拆分为单个空的JSP后,将其放入在jdk1.6上运行的开箱即用的Tomcat 6.0.37实例中,我仍然看到同样的事情。
我正在启动Tomcat,最大堆大小(-Xmx)为256m,并且在我的测试类下面发出大约282,000个请求后,堆空间用完了。
为了进行比较,我还创建了一个HttpServlet,它与JSP完成相同的操作,并修改了我的测试客户端来调用它,这将在一整天内运行而不会耗尽内存。
我已经开始尝试分析堆来弄清楚这里发生了什么,但并没有真正到达任何地方。 Soooo,这里发生了什么?
测试JSP
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%@ page contentType="text/plain"%>
<% System.out.println("Page requested: " + new Date()); %>
This is a test response
Java测试客户端
public static void main(String[] args) throws Exception {
int i=0;
while(true) {
java.net.URL url = new java.net.URL("http://localhost:8080/test.jsp");
InputStream is = url.openStream();
while(is.read() != -1) {
//nothing, just read the stream
}
is.close();
System.out.println("Requests made: " + i++);
}
}
答案 0 :(得分:5)
JSP请求隐式创建HTTP会话。您没有在HTTP客户端中维护HTTP会话,因此每次请求都会创建一个全新的HTTP会话。这些会话的到期时间默认为30分钟。显然所有这些请求都是在30分钟内被解雇的。
当您在servlet方法中执行request.getSession()
时,您将在servlet中遇到完全相同的问题。
为了“修复”这个“问题”(在现实世界中不太可能发生;另一方面,在准系统Tomcat实例上282K并发HTTP会话非常可观),要么在JSP中禁用隐式创建HTTP会话:
<%@page session="false">
或告诉客户端重复使用相同的HTTP会话,方法是在 while
循环之前通过以下行维护cookie:
CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
另一种方法是减少会话超时,以便服务器有机会在它导致堆溢出之前收获它们,例如:在web.xml
:
<session-config>
<session-timeout>5</session-timeout>
</session-config>
您可以实施HttpSessionListener
来跟踪HTTP会话的创建并销毁。