1

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

它有点像这样:

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

    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 并切换请求类型,执行请求的查询。然后,它将结果设置为Plain Old Java Object对查询表进行建模的形式,或java.util.ArrayList<POJO-Typed-Object>用于 DTO 上的多结果查询的形式,并将其发送回客户端。

它显然工作正常,问题是,经过一些查询,特别是具有大量行的查询,服务器应用程序内存不足。

PreparedStatements使用后关闭,ResultSets 也关闭,所以我不知道内存在哪里。

任何建议将不胜感激。

4

3 回答 3

2

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

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

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

解析 heapDump 后,您可以看到哪些对象正在持有内存。

是的,只是一个旁注:您为每个客户创建一个线程的解决方案将无法扩展。我会重新设计架构。

于 2013-05-06T19:37:53.473 回答
1

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

  1. 结果集的大小太大而无法放入 JVM 的堆空间。解决方案包括:
    • 尝试使用 -ms 和 -mx 设置调整堆大小。
    • 不是在遍历结果集时将整个对象集加载到集合中,而是将每个对象发生的“工作”放入 while (rs.next()) 循环中。您可以使用控制反转来保持代码松散耦合。
  2. 您产生的线程数比它们退出的速度快。这是一种拒绝服务。可能的解决方案:
    • 线程池
    • 更改您的 while 循环以使用活动连接数的计数器,并且仅在该数量小于某个定义的阈值时接受

ExecutorService java doc 页面有一个很好的例子,说明了如何将线程池与服务器套接字结合使用。

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

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath="C:\"
于 2013-05-06T19:50:57.583 回答
0

我得到的唯一原因OutOfMemoryError是当我有一些没有关闭的查询Cursorcursor.close();

于 2013-05-06T19:55:11.883 回答