【问题标题】:Why used heap is always increasing in my MINA application?为什么在我的 MINA 应用程序中使用的堆总是在增加?
【发布时间】:2012-12-04 08:48:03
【问题描述】:

我有一个应用程序,它由服务器和客户端两部分组成。

它是这样工作的:

客户端连接到服务器并发送一个字符串;服务器接收字符串并返回一个包含 10000 个元素的 ArrayList(通过转换字符串)。

我编写了一个类 (ClientConnector.java),它模拟许多客户端使用一个连接从服务器获取这 10000 个元素。

当我运行这两个程序时,服务器端没问题。然而在客户端,使用的堆总是在增加!我试图通过“null”来释放使用过的对象,但是使用过的内存还是越来越大。

http://s10.postimage.org/egf4ugrd5/mem.png

我的服务器端代码: 客户端.java

公共类客户端{

private static final int PORT = 7571;
ClientHandler handler = new ClientHandler("hey");
IoConnector connector;
boolean available = true;

public synchronized void setAvailable(boolean available) {
    this.available = available;
}

public synchronized boolean isAvailable() {
    return available;
}

public void starter() throws InterruptedException {

    Thread t = new Thread(new Runnable() {
        @Override
        public void run() {

            connector = new NioSocketConnector();
            connector.getSessionConfig().setReadBufferSize(2048);
            TextLineCodecFactory t = new TextLineCodecFactory(Charset.forName("UTF-8"));
            t.setEncoderMaxLineLength(20 * 150000);
            t.setDecoderMaxLineLength(20 * 150000);
            connector.getFilterChain().addLast("logger", new LoggingFilter());
            connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(t));

            connector.setHandler(handler);
            ConnectFuture future = connector.connect(new InetSocketAddress("localhost", PORT));
            future.awaitUninterruptibly();

            if (!future.isConnected()) {
                return;
            }

            IoSession session = future.getSession();
            session.getConfig().setUseReadOperation(true);
            session.getCloseFuture().awaitUninterruptibly();

            connector.dispose();
        }
    });
    t.start();
    Thread.sleep(300);
}

public void conClose() {
    connector.dispose();
}

public ClientHandler getHandler() {
    return handler;
}

public void reqInf() {
    handler.reqInfo();
}

public static void main(String[] args) {
    try {
        Client c = new Client();
        c.starter();
    } catch (InterruptedException ex) {
        System.out.println("error");
    }
}

}

ClientHandler.java

公共类 ClientHandler 扩展 IoHandlerAdapter {

long time;
private final String values;
IoSession session;

public ClientHandler(String values) {
    this.values = values;
}

@Override
public void sessionOpened(IoSession session) throws InterruptedException {
    this.session = session;
}

public ArrayList<String> convert(String str) {
    Gson gson = new Gson();
    return gson.fromJson(str, ArrayList.class);
}

@Override
public void messageReceived(IoSession session, Object message) throws InterruptedException {

    try {
        ArrayList<String> test = convert(message.toString());
        System.out.println("TIME : " + (System.currentTimeMillis() - time) + " strList:" + test.size());
        message = null;
        test = null;

    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

@Override
public void exceptionCaught(IoSession session, Throwable cause) {
    session.close();
    System.out.println(cause.toString());
}

@Override
public void sessionClosed(IoSession session) {

    System.out.println("Connection Lost");
}

public void reqInfo() {
    time = System.currentTimeMillis();
    session.write("test");
}

}

我的服务器端: 服务器.java

公共类服务器{

private static final int PORT = 7571; //TEST PORT
IoAcceptor acceptor = new NioSocketAcceptor();

public Server() throws IOException {
    TextLineCodecFactory t = new TextLineCodecFactory(Charset.forName("UTF-8"));
    t.setEncoderMaxLineLength(20*150000);
    t.setDecoderMaxLineLength(20*150000);
    acceptor.getFilterChain().addLast("logger", new LoggingFilter());
    acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(t));
    // acceptor.getFilterChain().addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool()));

    Executor executor = new ThreadPoolExecutor(5, 70, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());

    acceptor.getFilterChain().addLast("threadPool", new ExecutorFilter(executor));
    acceptor.setHandler(new ServerHandler());
    acceptor.getSessionConfig().setReadBufferSize(2048);
    acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 1000);

    //timer();

    acceptor.bind(new InetSocketAddress(PORT));
    System.out.println("***Mina Server is ready !");
    System.out.println("");
    System.out.println("");


}


public static void main(String[] args) throws IOException {
    Server m = new Server();
}

}

ServerHandler.java

公共类 ServerHandler 扩展 IoHandlerAdapter {

private final Logger logger = (Logger) LoggerFactory.getLogger(getClass());
IoSession sessions;
//Communication communication;

public ServerHandler() throws IOException {
    loader();
    // communication = new Communication(this);
}

@Override
public void sessionOpened(IoSession session) {
    // set idle time to 10 seconds
    session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE, 1000);
    System.out.println("Client Connected !!!");
    //session.setAttribute("Values: ");
    this.sessions = session;

}

public String toGSon(ArrayList<String> list) {
    Gson gson = new Gson();
    String str = gson.toJson(list);
    return str;
}
ArrayList<String> str = new ArrayList<String>();

public void loader() {
    for (int i = 0; i < 10000; i++) {
        str.add("test" + i);
    }
}

@Override
public void messageReceived(IoSession session, Object message) throws InterruptedException {

    long time = System.currentTimeMillis();
    session.write(toGSon(str));
    System.out.println("TIME : " + (System.currentTimeMillis() - time));

}

@Override
public void sessionIdle(IoSession session, IdleStatus status) {
    System.out.println("Socket #" + session.getId() + " is disconnecting... (IDLE)");
    session.close();
}

@Override
public void exceptionCaught(IoSession session, Throwable cause) {
    System.out.println("------------>" + cause.toString());
    session.close();
}

}

还有我的主班

公共类 ClientConnector {

public ClientConnector() throws InterruptedException {
    Client cl = new Client();
    cl.starter();
    while (true) {

        cl.reqInf();
        Thread.sleep(100);
    }
}

public static void main(String[] args) throws InterruptedException {
    ClientConnector cl = new ClientConnector();
}

}

【问题讨论】:

  • 你有没有在Heap增加的时候强行调用GC?
  • 你能分享你正在使用的分析工具的堆统计信息吗?
  • 我认为,手动调用 GC 不是正确的方法。这是统计数据s13.postimage.org/5dqc33k0n/mem2.png
  • 您应该发布重现问题的最少代码。还要正确地构造你的代码,比如首先是字段,然后是方法。这是一个没人愿意看的烂摊子。
  • 我知道,但这只是一次测试是否有泄漏或 GC 在那个时间段内没有运行:) t.setEncoderMaxLineLength(20*150000); 这行做什么?

标签: java performance memory mina


【解决方案1】:

我们的一位开发人员发现 Mina 的清理方式存在问题,并且已将补丁应用于 2.0.8 版。因为从今天起这是“快照”,你必须从 git 中获取它并自己构建它。这是从 git 获取它的命令:

混帐结帐 2.0

存储库 uri:

git 克隆 http://git-wip-us.apache.org/repos/asf/mina.git

【讨论】:

    【解决方案2】:

    您必须从客户端删除以下代码。

    session.getConfig().setUseReadOperation(true);
    

    以上代码会导致内存泄漏。

    【讨论】:

      【解决方案3】:

      此代码不足以得出准确的答案。

      堆大小不断增加,GC没有影响-->内存泄漏的迹象。

      您可能应该Profile您的应用程序并使用一些OQL Tools 来找出哪个类正在使用char[],这是查看堆转储的罪魁祸首

      【讨论】:

      • 其实Server端和Client端都运行在各自的线程上,互相监听。这种情况的原因是否可能是线程局部变量?请查看 ClientHandler 上的 messageReceived 方法。 “消息”对象是一个巨大的字符串。 GC是否有可能每次都忽略这个字符串?
      • 这应该不是问题,除非两个线程都释放未使用的引用。正如你所说,有很多代码唯一的方法是找出使用 OQL 使用引用的位置。
      猜你喜欢
      • 2011-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多