2013-05-06 39 views
1

我正在处理一个应用程序来管理数据库。它被设计成服务器/客户端,服务器处理所有数据库的事务。OutOfMemoryException几个查询后

这有点是这样工作的:

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

    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的形式,该机型的查询表,或multiresult查询的DTO一个java.util.ArrayList<POJO-Typed-Object>,并将其发送回客户端的结果。

它显然工作正常,问题是,一些查询后,特意用行大量的那些,服务器应用程序运行的内存。

PreparedStatements在使用后关闭,因此ResultSet s,所以我不知道内存在哪里。

任何建议将不胜感激。

+0

当你只有大疑问之一,它给太例外? – 2013-05-06 19:27:11

+0

不,我可以在没有任何问题的情况下进行5或6个包含12,000行以上的查询,但是从这一点来看,它会在下一个例外情况下给出例外。 – Noe 2013-05-06 19:28:32

+0

你确定线程正在退出吗?您为每个连接创建一个新线程,以便假定它们是自我退出的。 – Brandon 2013-05-06 19:30:46

回答

1

既然你提到的OutOfMemoryError往往跟随大结果集,我看到两个潜在的内存问题:

  1. 结果集的尺寸太大,以适应JVM的堆空间。解决方案包括:
    • 试图调整与-ms和-mx设置堆大小。
    • 而不是在遍历结果集的同时将整个对象集合加载到集合中,请为每个对象执行“工作”并将其放入while(rs.next())循环中。您可以使用inversion of control来保持代码松耦合。
  2. 您产生的线程速度比它们退出的速度快得多。这是一种拒绝服务。可能的解决方案:
    • Thread pool
    • 更改while循环使用的活动连接数的计数器,并只接受时,这个数字是<一些定义的阈值

ExecutorService java doc page有一个很好的例子如何结合服务器套接字使用线程池。

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

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

我已经做好了转储,并用VisualVM打开它。我看到很多char []和Strings实例,它们使转储文件的80%成为... – Noe 2013-05-06 20:06:29

+0

非常好...所以你有一个关于内存在哪里的想法。现在弄清楚这些字符串是什么。它们是SQL查询结果集的一部分吗?你可以在应用程序外部自己运行查询并查看那些相同的字符串吗?我认为你需要收集有关并发连接数的统计信息。您还不知道是否由于单个结果集而导致字符串数量很高,或者因为一次存储器中有多个结果集。 – Brandon 2013-05-06 20:18:51

+0

好了,完成了。似乎Java中InputStream的/ OutputStream存在内存泄漏,建议的解决方法是不时触发'outputStream.reset();'。这是真的,因为在堆转储中,我可以看到'ObjectInputStream $ HandlerTable'内的大块,所以在玩了一些reset()之后,一切都变成了桃子和肉汁。非常感谢你的帮助! PS。我还使用您建议的ExecutorService实现线程池。 – Noe 2013-05-08 14:43:51

2

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

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

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

解析heapDump后,你可以看到什么对象持有的内存。

,是的,只是一个侧面说明:您的线程解决方案为每个客户端不能扩展。我会重新设计架构。

+0

谢谢,@Funtik,什么可能是更好的方法? – Noe 2013-05-06 19:43:21

+0

取决于您尝试创建的应用程序的类型。我认为您可以轻松地使用Web服务/ EJB/RMI技术重写您的架构。有那么多的图书馆,没有必要发明自行车。 – WeMakeSoftware 2013-05-06 19:48:18

0

在那里我得到了OutOfMemoryError是,当我有一些疑问在那里我没有关闭的唯一原因Cursorcursor.close();