几次查询后出现OutOfMemoryException

时间:2013-05-06 19:23:02

标签: java mysql memory-management

我正在开发一个管理数据库的应用程序。它被设计为服务器/客户端,服务器处理所有数据库的事务。

它有点像这样:

  • 当服务器启动时,它会打开一个套接字并开始侦听端口。
  • 当客户端启动时,它会搜索套接字/端口,如果打开,服务器会启动一个新线程:

    while (true) {
        new Thread(new comm.Protocol(serverSocket.accept()).start();
    }
    

进入线程后,服务器会创建所需的通信对象(ObjectInputStream& ObjectOutputStream),并等待客户端发送登录信息。收到后,服务器会尝试创建新连接:

    Class.forName("com.mysql.jdbc.Driver");
    connection=DriverManager.getConnection(dbName, username, password);

如果成功,它会保存连接并继续循环等待客户端的请求。与DTO进行通信,DTO包含客户端的请求类型和查询所需的数据对象。服务器获取DTO并切换请求类型,执行请求的查询。然后,它以Plain Old Java Object的形式设置结果,该java.util.ArrayList<POJO-Typed-Object>对查询表进行建模,或者在DTO上为多结查询设置PreparedStatements并将其发送回客户端。

显然工作正常,经过一些查询后,特别是那些行数很多的服务器应用程序内存不足。

ResultSet在使用后关闭,{{1}}也是如此,所以我不知道内存在哪里。

任何建议都将不胜感激。

3 个答案:

答案 0 :(得分:2)

您的应用程序中可能存在内存泄漏。 要测试实际拥有内存的内容,可以使用这些选项启动Java程序

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath="C:\"

程序崩溃后,您将在C:\驱动器中获得堆转储。 有几种工具可用于分析堆转储(取决于您正在使用的IDE)。 对于eclipse,您可以下载http://www.eclipse.org/mat/

解析heapDump后,您可以看到哪些对象占用了内存。

是的,只是旁注:你的每个客户的线程解决方案都无法扩展。我会重新设计这个架构。

答案 1 :(得分:1)

由于您提到OutOfMemoryError倾向于遵循大型结果集,因此我发现了两个潜在的内存问题:

  1. 结果集的大小太大,无法容纳JVM的堆空间。方案包括:
    • 尝试使用-ms和-mx设置调整堆大小。
    • 不是在迭代结果集时将整个对象集加载到集合中,而是为每个对象执行“work”并将其放入while(rs.next())循环中。您可以使用inversion of control来保持代码松散耦合。
  2. 你产生的线程数量太快而不是退出。这是一种拒绝服务。可能的解决方案:
    • Thread pool
    • 更改您的while循环以使用活动连接数的计数器,并且仅当该数字为&lt;时才接受。一些定义的阈值
  3. ExecutorService java doc page有一个很好的例子,说明如何将线程池与服务器套接字结合使用。

    我还推荐@Funtik在另一个答案中推荐的HeapDumpOnOutOfMemoryError和HeapDumpPath参数。

    -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath="C:\"
    

答案 2 :(得分:0)

我获得OutOfMemoryError的唯一原因是当我有一些查询时我没有用Cursor关闭cursor.close();