简体   繁体   English

Java MySQL JDBC内存泄漏

[英]Java MySQL JDBC Memory Leak

Ok, so I have this program with many (~300) threads, each of which communicates with a central database. 好的,所以我有这个程序有很多(~300)个线程,每个线程都与一个中央数据库通信。 I create a global connection to the DB, and then each thread goes about its business creating statements and executing them. 我创建了一个到DB的全局连接,然后每个线程都会创建业务创建语句并执行它们。

Somewhere along the way, I have a massive memory leak. 在某个地方,我有一个巨大的内存泄漏。 After analyzing the heap dump, I see that the com.mysql.jdbc.JDBC4Connection object is 70 MB, because it has 800,000 items in "openStatements" (a hash map). 在分析堆转储后,我看到com.mysql.jdbc.JDBC4Connection对象是70 MB,因为它在“openStatements”(哈希映射)中有800,000个项目。 Somewhere it's not properly closing the statements that I create, but I cannot for the life of me figure out where (every single time I open one, I close it as well). 在某个地方它没有正确地关闭我创建的语句,但我不能为我的生活弄清楚在哪里(每次打开一个,我也关闭它)。 Any ideas why this might be occurring? 有什么想法可能会发生吗?

I had exactly the same problem. 我有完全相同的问题。 I needed to keep 1 connection active for 3 threads and at the same time every thread had to execute a lot of statements (the order of 100k). 我需要为3个线程保持1个连接活动,同时每个线程必须执行大量语句(100k的顺序)。 I was very careful and I closed every statement and every resultset using a try....finally... algorithm. 我非常小心,我使用try .... finally ...算法关闭了每个语句和每个结果集。 This way, even if the code failed in some way, the statement and the resultset were always closed. 这样,即使代码以某种方式失败,语句和结果集也始终关闭。 After running the code for 8 hours I was suprised to find that the necessary memory went from the initial 35MB to 500MB. 运行代码8小时后,我惊讶地发现必要的内存从最初的35MB到500MB。 I generated a dump of the memory and I analyzed it with Mat Analyzer from Eclipse. 我生成了一个内存转储,我用Eclipse的Mat Analyzer进行了分析。 It turned out that one com.mysql.jdbc.JDBC4Connection object was taking 445MB of memory keeping alive some openStatements objects wich in turn kept alive aroun 135k hashmap entries, probably from all the resultsets. 事实证明,一个com.mysql.jdbc.JDBC4Connection对象占用了445MB的内存,保留了一些openStatements对象,而这些对象依次保留了135k hashmap条目,可能来自所有结果集。 So it seems that even if you close all you statements and resultsets, if you do not close the connection, it keeps references to them and the GarbageCollector can't free the resources. 因此,即使您关闭所有语句和结果集,如果不关闭连接,它也会保留对它们的引用,并且GarbageCollector无法释放资源。

My solution : after a long search I found this statement from the guys at MySQL: 我的解决方案 :经过长时间的搜索,我发现MySQL的人员发表了这样的声明:

"A quick test is to add " dontTrackOpenResources=true " to your JDBC URL. If the memory leak goes away, some code path in your application isn't closing statements and result sets." “快速测试是将” dontTrackOpenResources = true “添加到JDBC URL。如果内存泄漏消失,应用程序中的某些代码路径不会关闭语句和结果集。”

Here is the link: http://bugs.mysql.com/bug.php?id=5022 . 这是链接: http//bugs.mysql.com/bug.php?id = 5022 So I tried that and guess what? 所以我试过了,猜猜怎么着? After 8 hours I was around 40MB of memory required, for the same database operations. 8小时后,对于相同的数据库操作,我需要大约40MB的内存。 Maybe a connection pool would be advisible, but if that's not an option, this is the next best thing I came around. 也许连接池是可取的,但如果这不是一个选项,这是我遇到的下一个最好的事情。

Once upon a time, whenever my code saw "server went away," it opened a new DB connection. 曾几何时,每当我的代码看到“服务器消失”时,它就会打开一个新的数据库连接。 If the error happened in the right (wrong!) place, I was left with some non-free()d orphan memory hanging around. 如果错误发生在正确(错误!)的地方,我会留下一些非自由()d孤儿记忆。 Could something like this account for what you are seeing? 像这样的东西可以说明你所看到的吗? How are you handling errors? 你是如何处理错误的?

You know unless MySQL says so, JDBC Connections are NOT thread safe. 你知道,除非MySQL这么说,JDBC Connections不是线程安全的。 You CANNOT share them across threads, unless you use a connection pool. 除非使用连接池,否则不能跨线程共享它们。 In addition as pointed out you should be try/finally guaranteeing all statements, result sets, and connections are closed. 另外,正如所指出的那样,您应该尝试/最终保证关闭所有语句,结果集和连接。

Without seeing your code (which I'm sure is massive), you should really consider some sort of more formal thread pooling mechanism, such as Apache Commons pool framework, Spring's JDBC framework, and others. 如果没有看到你的代码(我确信它是巨大的),你应该考虑某种更正式的线程池机制,例如Apache Commons池框架,Spring的JDBC框架等。 IMHO, this is a much simpler approach, since someone else has already figured out how to effectively manage these types of situations. 恕我直言,这是一个更简单的方法,因为其他人已经想出如何有效地管理这些类型的情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM