论坛首页 Java企业应用论坛

Tomcat异步Servlet占用内存问题

浏览 4010 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-06-11   最后修改:2012-06-11

Author:xiaohanghu

Date: 2012/6/11

Email:huhang1986@gmail.com

 

进行auto-comet(http://code.google.com/p/auto-comet/)连接数测试的时候,发现Tomcat7内存增长飞快,3000个连接的时候占用了250MB内存,导致堆溢出。

 

于是编写了一个测试类,查找Tomcat占用内存的问题:

 

 

import java.io.IOException;
import java.io.Serializable;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.AsyncContext;

//import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.InputBuffer;
import org.apache.catalina.connector.Request;
import org.apache.catalina.core.AsyncContextImpl;
import org.auto.comet.ConcurrentPushSocket;
import org.auto.comet.PushSocket;

/**
 * org.apache.catalina.connector.Request
 * 对象占用内存非常多,导致comet连接占用内存非常多(平均一个连接占用内存8KB+)
 * 
 * @author xiaohanghu
 */
public class MemoryTest {

 private static final MemoryMXBean memoryMXBean = ManagementFactory
   .getMemoryMXBean();

 protected static Map<Serializable, Object> socketStore = new ConcurrentHashMap<Serializable, Object>();

 // protected static Map<Serializable, PushSocket> socketStore =
 // Collections.EMPTY_MAP;

 public static void main(String[] args) throws IOException {

  for (int i = 0; i < 8000; i++) {
   // Request request = new Request();
   // socketStore.put("asdfsdfsadf" + i, new ConcurrentPushSocket());
   // AsyncContext asyncContext = new AsyncContextImpl(request);
   // socketStore.put("asdfsdfsadfa" + i, asyncContext);
   // socketStore.put("asdfsdfsadfa" + i, request);// 占内存非常多
   // request.finishRequest();
   InputBuffer inputBuffer = new InputBuffer();
   socketStore.put("asdfsdfsadfa" + i, new InputBuffer());// 罪魁祸首
   inputBuffer.close();
  }
  MemoryUsage memoryUsage = memoryMXBean.getHeapMemoryUsage();
  long usedBytes = memoryUsage.getUsed();

  System.out.println("used :" + usedBytes / 1024 / 1024 + " MB");

 }
}

 

 

 

原来罪魁祸首是org.apache.catalina.connector.Request类的一个实例变量InputBuffer导致的:

 

    /**
     * The associated input buffer.
     */
    protected InputBuffer inputBuffer = new InputBuffer();

  

而org.apache.catalina.connector.InputBuffer的默认大小是8*1024!也就是说每个Request对象占用内存大于8KB。而在异步的AsyncContext对象没有回收前,这8KB的内存也无法回收!在request读取完毕后,InputBuffer对象就已经没有用了,这个算得上是Tomcat7的严重的内存问题了!

   发表时间:2012-06-12  
那么去tomcat的邮件列表里面反应一下吧。和他们讨论一下这个问题。
0 请登录后投票
   发表时间:2012-06-12  
已经提交到他们的BUG列表了。
0 请登录后投票
   发表时间:2012-06-13  
Tomcat的开发人员,回复无法修复,这个跟他们的整体设计有关:
https://issues.apache.org/bugzilla/show_bug.cgi?id=53401

The InputBuffer may not be necessary in your use case, but it is required in
the general case both for performance and for pipe-lining.

WebSocket can and does use lighter weight objects and should be much more
scalable.
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics