2012-06-11 2 views
0

У меня есть самописное приложение Java - небольшой почтовый монитор. Он работает с базой данных MySQL, в которой есть таблица, которая заполняется где-то в другом месте. Он просматривает таблицу и отправляет письма, поскольку записи отображаются в таблице.Java: многопоточная почтовая программа утечки памяти

Моя проблема в том, что приложение утечки памяти. Я был совершенно уверен, что этого не произошло, поскольку объем всего, что я использую, кажется, исчезает, заставляя все объекты использовать сборщик мусора. Но через некоторое время (в зависимости от -Xmx I pass) приложение останавливается с ошибкой OutOfHeapSpace.

Я не могу опубликовать весь код, поскольку он больше не мой, но я попытался его воссоздать с помощью псевдокода.

Main: 
    Startup 
    Create .lock file (FileChannel) 
    Instantiate Main Class 

Constructor Main: 
    Class.ForName for the MySQL driver 
    Read properties file (settings) 
    Create connection object (MySQL) 
    Fetch unsent mail ids (ArrayList) 
    while(true) 
    while have more mail ids 
     new Thread(Top Mail ID, MySQL Connection object, Sleep Time, Blacklist); 
    end while 
    if have no more mail ids in ArrayList: 
     sleep for a number of seconds (usually 300) 
    end if 
    end while 

Constructor Thread: 
    Prepare Statement 
    New Thread(this).start(); 
    Sleep 

Thread run(): 
    Select Record by passed Mail ID 
    Extract everything (Sender, Receiver, Subject etc.) 
    Check Blacklist, return if matched 
    Extract Attachments as blobs 

То, что я пытался до сих пор:

jvisualvm показал мне, как изменения памяти с течением времени. То, что я вижу, - это зубчатая линия в куче: распределение и сбор памяти происходит регулярно, однако после коллекции всегда выделяется больше памяти, чем после последней коллекции. количество потоков кажется прекрасным, оно всегда падает до стандартного номера.

Сумма информации в jvisualvm для меня слишком велика. Там есть нити, которые я не могу определить, нити, которые я создаю, не перечислены как мой класс, поэтому трудно точно определить, что такое «мой» код.

Может ли кто-нибудь распознать какие-либо распространенные ошибки многопоточности в моем псевдокоде или рекомендовать какие-либо инструменты, которые позволят мне легче определить мои утечки?

спасибо.

Редактировать 1: Доступ к данным через объект соединения, который передается всем потокам, синхронизируется сам по себе.

Edit 2: Я проверил количество писем, которые unsendable (как эти пребывания в базе данных), существует около 10.

Редактировать 3: я нашел Eclipse, анализатор памяти, установил его, и он намекнул на проблема. Похоже, что использование PreparedStatements при сохранении одного объекта соединения сохраняет HashMap всех PreparedStatements, когда-либо выполняемых над этим соединением внутри него, поэтому добавляет все данные, когда-либо выбранные для него. Я полагался на PreparedStatement, выходящий из сферы действия и собираемый. Я переписал и попытаюсь, если это устранит проблему.

+1

В таких случаях я бы хотя бы попытался найти FindBugs один раз. –

+0

Я не знал этого инструмента. Установка сейчас. Спасибо. – 0xCAFEBABE

ответ

0

Если это кому-то интересно, я исправил проблему с памятью.

Приложение фактически не утечки памяти. Когда я передавал один и тот же объект соединения, кажется, что он сохранил результат каждого подготовленного оператора, выполняемого против него, в большом хэш-файле.Поэтому использование памяти постоянно увеличивалось. Я нашел это с помощью кучи кучи, созданного с помощью jvisualvm и загруженного в Eclipse Memory Analyzer.

Я переписал приложение для использования ThreadPool (Cached), открыл выделенное соединение для каждого потока и закрыл соединение в конце каждого потока.

1

Из вашего псевдокода кажется, что вы создаете поток для каждого отправленного сообщения, что не кажется таким эффективным. Я знаю, что вы упомянули, что количество потоков является «нормальным», но, как представляется, код указывает на другое. Не могли бы вы попытаться использовать пул потоков вместо этого, в результате чего у вас есть ограниченное число работников потоков и передайте им работу через какую-то очередь заданий.

Знаете ли вы, есть ли какие-либо ошибки, которые могут привести к тому, что потоки не будут завершены или не будут «висящими»? Это может быть утечка памяти, поэтому ознакомьтесь с кодом обработки ошибок.

В прошлом я использовал jprofiler с некоторым успехом, возможно, это была бы полезная альтернатива.

+0

Благодарим вас за ввод. – 0xCAFEBABE

Смежные вопросы