Утечка памяти в Java MySQL JDBC - PullRequest
       15

Утечка памяти в Java MySQL JDBC

9 голосов
/ 23 апреля 2011

Хорошо, у меня есть эта программа со многими (~ 300) потоками, каждый из которых связывается с центральной базой данных. Я создаю глобальное соединение с БД, а затем каждый поток занимается своим делом, создавая операторы и выполняя их.

Где-то по пути у меня огромная утечка памяти. Проанализировав дамп кучи, я вижу, что объект com.mysql.jdbc.JDBC4Connection имеет размер 70 МБ, поскольку он содержит 800 000 элементов в «openStatements» (хэш-карте). Где-то это неправильно закрывает утверждения, которые я создаю, но я не могу на всю жизнь выяснить, где (каждый раз, когда я открываю одно, я тоже закрываю его). Есть идеи, почему это может происходить?

Ответы [ 4 ]

22 голосов
/ 14 октября 2011

У меня была точно такая же проблема. Мне нужно было поддерживать 1 соединение активным для 3 потоков, и в то же время каждый поток должен был выполнять много операторов (порядка 100 КБ). Я был очень осторожен и закрыл каждое утверждение и каждый набор результатов, используя алгоритм try .... finally ... Таким образом, даже если код каким-то образом завершился неудачей, оператор и набор результатов всегда были закрыты. После запуска кода в течение 8 часов я был удивлен, обнаружив, что необходимая память выросла с начальных 35 МБ до 500 МБ. Я создал дамп памяти и проанализировал его с помощью Mat Analyzer из Eclipse. Оказалось, что один объект com.mysql.jdbc.JDBC4Connection занимал 445 МБ памяти для поддержки некоторых объектов openStatements, которые, в свою очередь, поддерживали около 135 тыс. Записей хэш-карт, вероятно, из всех наборов результатов. Таким образом, кажется, что даже если вы закроете все свои операторы и наборы результатов, если вы не закроете соединение, он сохранит ссылки на них, и GarbageCollector не сможет освободить ресурсы.

Мое решение : после долгих поисков я нашел это утверждение от парней из MySQL:

"Быстрый тест - добавить" dontTrackOpenResources = true"к URL-адресу JDBC. Если утечка памяти уходит, некоторые пути кода в вашем приложении не закрывают операторы и наборы результатов. "

Вот ссылка: http://bugs.mysql.com/bug.php?id=5022. Итак, я попробовал это и угадайте, что? Через 8 часов мне потребовалось около 40 МБ памяти для тех же операций с базой данных. Может быть, пул соединений был бы целесообразен, но если это не вариант, это следующая лучшая вещь, которую я нашел.

0 голосов
/ 23 апреля 2011

Вы знаете, если MySQL не скажет так, соединения JDBC НЕ являются поточно-ориентированными. Вы НЕ МОЖЕТЕ делиться ими между потоками, если только вы не используете пул соединений. Кроме того, как указывалось, вы должны попытаться / наконец гарантировать, что все операторы, наборы результатов и соединения закрыты.

0 голосов
/ 23 апреля 2011

Не видя ваш код (который, я уверен, является массивным), вы действительно должны рассмотреть какой-то более формальный механизм пула потоков, такой как инфраструктура пула Apache Commons, среда Spring JDBC и другие. ИМХО, это гораздо более простой подход, так как кто-то уже понял, как эффективно управлять такими ситуациями.

0 голосов
/ 23 апреля 2011

Когда-то, когда мой код видел, что «сервер ушел», он открывал новое соединение с БД. Если ошибка произошла в правильном (неправильном!) Месте, у меня осталась несвободная () d сиротская память. Может ли что-то вроде этого объяснить то, что вы видите? Как вы справляетесь с ошибками?

...