На Java с MySQL утечка памяти с JDBC
Ok, поэтому у меня есть эта программа со многими (~300) потоками, каждый из которых взаимодействует с центральной базой данных. Я создаю глобальное соединение с БД,а затем каждый поток выполняет свои бизнес-инструкции и выполняет их.
где-то по пути, у меня жуткая утечка памяти. Проанализировав дамп "кучи", я вижу, что com.для MySQL.интерфейс jdbc.Объект JDBC4Connection составляет 70 Мб, поскольку он имеет 800 000 элементов в "openStatements" (хэш-карте). Где-то это неправильно. закрывая утверждения, которые я создаю, но я не могу понять, где (каждый раз, когда я открываю один, я закрываю его). Есть идеи, почему это может произойти?
4 ответов
вы знаете, если MySQL не говорит так, соединения JDBC не являются потокобезопасными. Вы не можете делиться ими между потоками, если не используете пул соединений. Кроме того, как указано, вы должны попробовать/наконец гарантировать, что все операторы, результирующие наборы и соединения закрыты.
У меня была точно такая же проблема. Мне нужно было сохранить 1 соединение активным для 3 потоков, и в то же время каждый поток должен был выполнить много операторов (порядка 100k). Я был очень осторожен, и я закрыл каждый оператор и каждый resultset, используя try....в конечном счете... алгоритм. Таким образом, даже если код каким-то образом не удался, оператор и набор результатов всегда были закрыты. После запуска кода в течение 8 часов я был удивлен, обнаружив, что необходимая память пошла от начального 35MB до 500МБ. Я сгенерировал дамп памяти и проанализировал его с помощью Mat Analyzer из Eclipse. Оказалось, что один ком.для MySQL.интерфейс jdbc.Объект JDBC4Connection принимал 445 МБ памяти, сохраняя живыми некоторые объекты openStatements, которые, в свою очередь, поддерживали жизнь вокруг 135k записей hashmap, вероятно, из всех результирующих наборов. Таким образом, кажется, что даже если вы закрываете все операторы и результирующие наборы, если вы не закрываете соединение, оно сохраняет ссылки на них, и GarbageCollector не может освободить ресурсы.
мое решение: после долгого поиска я нашел это заявление от парней в MySQL:
"быстрый тест, чтобы добавить"dontTrackOpenResources=true " на Ваш URL JDBC. Если утечка памяти уходит, некоторый путь кода в вашем приложении не закрывает операторы и результирующие наборы."
вот ссылка:http://bugs.mysql.com/bug.php?id=5022. Я попробовал, и знаешь что? После 8 часов я был около 40MB памяти требуется для тех же операций с базой данных. Возможно, пул соединений был бы целесообразным, но если это не вариант, это следующая лучшая вещь, которую я нашел.
однажды, когда мой код увидел, что "сервер ушел", он открыл новое соединение с БД. Если ошибка произошла в правильном (неправильном!) место, я остался с какой-то несвободной()D сиротской памятью, висящей вокруг. Может ли что-то подобное объяснить то, что вы видите? Как вы справляетесь с ошибками?
Не видя вашего кода (который, я уверен, массивен), вы действительно должны рассмотреть какой-то более формальный механизм объединения потоков, такой как Apache Commons Pool framework, Spring JDBC framework и другие. ИМХО, это гораздо более простой подход, так как кто-то уже придумал, как эффективно управлять этими ситуациями.