4

我正在尝试在我们的 Tomcat Java Web 应用程序中发生内存泄漏,并认为我在向我们的一个 JSP 发出重复请求时发现了它。但是,在将其剥离为单个空 JSP 并放入运行在 jdk1.6 上的开箱即用的 Tomcat 6.0.37 实例之后,我仍然看到相同的情况。

我以 256m 的最大堆大小 (-Xmx) 启动 Tomcat,并且在下面的测试类发出大约 282,000 个请求后,堆空间不足。

作为比较,我还创建了一个与 JSP 执行相同操作的 HttpServlet,并修改了我的测试客户端以改为调用它,并且它将运行一整天而不会耗尽内存。

我已经开始尝试分析堆以弄清楚这里发生了什么,但并没有真正到达任何地方。呜呜呜,这是怎么回事??

测试 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++);
  }
}
4

1 回答 1

5

JSP 请求隐式创建 HTTP 会话。您没有在 HTTP 客户端中维护 HTTP 会话,因此每个请求都会创建一个全新的 HTTP 会话。默认情况下,这些会话的过期时间为 30 分钟。显然,所有这些请求都在 30 分钟内被解雇。

当您使用 servlet 方法时,您将在 servlet 中遇到完全相同的问题request.getSession()

为了“修复”这个“问题”(这在现实世界中不太可能发生;另一方面,准系统 Tomcat 实例上的 282K 并发 HTTP 会话相当可观),要么禁用 JSP 中 HTTP 会话的隐式创建:

<%@page session="false">

或者通过在循环之前通过以下行维护 cookie 来告诉客户端重用相同的 HTTP 会话:while

CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));

另一种方法是减少会话超时,以便服务器有机会在导致堆溢出之前获取它们,例如到 5 分钟,如下所示web.xml

<session-config>
    <session-timeout>5</session-timeout>
</session-config>

您可以实现一个HttpSessionListener来跟踪 HTTP 会话的创建和销毁。

于 2013-10-03T19:00:53.897 回答