[java] утечка памяти

oleg1331

Java 1.5
профилировщик jmp
Программа, которая по своей сути представляет собой перевод данных из одной БД в другу с некоторой обработкой. То есть в цикле однотипные операции.
Базы большие, но уже на 50.000 записей вся память утекает.
вот заголовок дампа jmp
 class_name      #instaces       max #instances  size    #GC     tenure
--------------------------------------------------------------
Total 354414 486045 62065880 927800 4872186
byte[] 65348 65351 46652496 49368 922722
com.mysql.jdbc.ResultSetImpl 21680 21680 3642240 10 309991
java.lang.Object[] 84293 84295 2557224 38612 1189466
com.mysql.jdbc.PreparedStatement 10843 10843 2515576 0 155000
char[] 14090 55793 1821952 266946 162594
com.mysql.jdbc.Field 10841 10841 1561104 16 155015
java.util.ArrayList 21743 21743 521832 10957 310078
int[] 22092 30261 482728 72120 310291
com.mysql.jdbc.PreparedStatement$ParseInfo 10843 10843 433720 0 155018
boolean[] 21697 21697 348528 0 310051
java.lang.String 14261 38319 342264 160365 159676
java.util.HashMap$Entry 11965 14179 287160 25967 155531
com.mysql.jdbc.DatabaseMetaData 10845 10845 260280 0 155021
com.mysql.jdbc.RowDataStatic 10841 10841 260184 4 155015
com.mysql.jdbc.ByteArrayRow 7919 7919 126704 288 103804
java.lang.Object 10863 10863 86904 5 155023
java.lang.reflect.Field 314 398 22608 89 314
short[] 188 231 20744 314 241
java.lang.Class 183 183 17568 0 226
com.mysql.jdbc.ConnectionPropertiesImpl$BooleanConnectionProperty 206 206 13184 0 412

То, что дальше - там совсем мелочи. То есть память отжирается где-то в при работе с мускулем. Кто-нибудь сталкивался с подобной проблемой, как решать и в каком направлении стоит смотреть?

SPARTAK3959

Если есть возможность использовать java 1.6 можно воспользоваться фичей eclipse 3.4 "what links here". Для нахождения утекших объектов можно использовать глобальный WeakHashMap. Либо найти профайлер который показывает графы объектов.

oleg1331

возможность использовать 1.6 - есть. а вот возможности отладки в графическом интерфейсе - нет. сервер, консоль, линукс :)
а можно как-то задампить всю информацию в текстовый файл, который потом на локальной машине в граф. интерфейсе просматривать?

SPARTAK3959

Eclipse вроде поддерживает удаленную отладку (надеюсь приложение запускается из командной строки, а не каким-нибудь tomcat'ом но я ни разу не пробовал.

psm-home

Можно сдампить хип
jmap -dump:format=b,file=heap.dump <pid>  
потом натравить на дамп хипа jhat
 jhat.exe -J-mx512m heap.dump 
Зайти броузером на 7000 порт и попробовать побродить по хипу. А вообще я б JProfiler взял, он конечно недешевый, но можно поюзать нелицензионный, если совесть позволит. Указываешь при запуске приложения на сервере использовать его profiling agent, а GUI запускаешь на рабочей станции и с комфортом разбираешься что да как.

oleg1331

спасибо. как-нибудь на досуге попробую разобраться.

Hastya

ну как бы самые тупые соображения
- все ли JDBC-объекты закрываютя?
- в чем выражается утекание памяти, как ты проверял расход памяти
- пробовал ли смотреть verbosegc и что там с кучей происходит

katrin2201

Судя по дампу много резалтссетов и припейрд стейтментов. Так что ты прав видимо.

pitrik2

перевод данных из одной БД в другу с некоторой обработкой
ну если там есть большущая табличка
и ты ее сначала всю выбираешь в память а потом обрабатываешь то вот и будет огромный расход памяти
тойсть во-первых нада убедиться что ты эти данные целиком в памяти не держишь, тоесть выбрал часть обработал записал и отдал мусоросборщику
во-вторых надо понять как работает jdbc майскулевский, может там разные версии jdbc по-разному себя ведут, можно ли там вообще кэшем резалтсета управлять...
потом есть ли в базе длинные данные, типа CLOB/BLOB?
их надо и/о стримами обрабатывать а не выбирать все в огромный byte[]
профайлеры это конечно хорошо, но зачастую гораздо больше можно понять сделав логгирование основных операций
(в log4j TRACE в java logging FINEST)
типа: открыт резалтсет с id таким-то, закрыт резалтсет с id таким-то из него было выбрано столько то записей

oleg1331

- все ли JDBC-объекты закрываютя?

jdbc всего два, они постоянно используются
- в чем выражается утекание памяти, как ты проверял расход памяти

слежением за тем, что с памятью происходит во время работы. постоянный рост от 50 мб до 4ГБ с учетом свопа - я думаю очевидно, что это утечка. При алгоритме, который в цикле выполняет одни и те же операции и ничего в памяти (по идее) хранить не должен.
пробовал ли смотреть verbosegc и что там с кучей происходит

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

Gaishnik

- все ли JDBC-объекты закрываютя?

jdbc всего два, они постоянно используются

Сутя по всему, ты подразумеваешь под JDBC объектами только Connection'ы. Закрывать надо также Statement'ы и ResultSet'ы

bleyman

сервер, консоль, линукс
А ты поставь на сервере хвинды, гном какой-нибудь и эклипсу, на своём компе xming и сиди в ней графически, лол.

Marinavo_0507

надеюсь приложение запускается из командной строки, а не каким-нибудь tomcat'ом
если в гугле набрать tomcat , то он сам продолжает: remote debug
и, что характерно, даёт ссылки на инструкции

SPARTAK3959

Круто, не знал. И видимо не я один, раз народ постоянно спрашивает ;)

pitrik2

Сутя по всему, ты подразумеваешь под JDBC объектами только Connection'ы. Закрывать надо также Statement'ы и ResultSet'ы
уточню
когда закрываешь коннекшен, то все остальное автоматически закроется
стейтменты надо закрывать сразу после их использования, это понятно
а вот резалтсеты не надо закрывать вообще
они сами закрываются 1) если закрыть стейтмент (или коннекшен) 2) если в стейтменте открыть новый резалт сет
если этих двоих пунктов не происходит а резалт сет надо закрыть - то это ОЧЕНЬ странно

Hastya

они сами закрываются 1) если закрыть стейтмент (или коннекшен) 2) если в стейтменте открыть новый резалт сет
Это в спецификации. Как ведет себя драйвер MySql - неизвестно. :)

pitrik2

ну можно же джаднуть и посмотреть :)

katrin2201

если этих двоих пунктов не происходит а резалт сет надо закрыть - то это ОЧЕНЬ странно
CallableStatement.executeQuery в цикле с разными параметрами но одним и тем же запросом.
outParameter - курсор. На примере оракла - оно само не закрывается.
Думаю, еще полно примеров, когда резалтсет не будет закрыт при шаренном запросе в цикле.

katrin2201

а в спецификации точно есть пункт 2?

pitrik2

а в спецификации точно есть пункт 2?
джавадок к резалтсету
A ResultSet object is automatically closed when the Statement object that generated it is closed, re-executed, or used to retrieve the next result from a sequence of multiple results.
а вот джавадок к стейтменту:
All execution methods in the Statement interface implicitly close a statment's current ResultSet object if an open one exists.
но к препареду и коллаблу такого джавдока нет
и как бы {@inheritDoc} не стоит
тоесть реализация может чо угодно делать :(
Оставить комментарий
Имя или ник:
Комментарий: