![]() |
|
Модераторы: LSD, AntonSaburov |
![]()
|
|
| Дрон |
|
|||
![]() Java-ненавистник :) ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3179 Регистрация: 29.12.2002 Где: Санкт-Петербург Репутация: 6 Всего: 93 |
Очередной неприятный сюрприз от Java.
Есть приложение, работающее с фотографиями. Основную часть времени оперативной памяти для работы требуется не очень много (несколько сотен мегабайт), но в некоторых случаях может понадобится и гигабайт для обработки очень больших фотографий. Если указать параметр -Xmx1024m, то JVM по ходу работы радостно занимает всю эту память, не вызывая сборщик мусора, даже когда память уже не нужна. При этом если я тестирую на своём ноутбуке у которого всего 1.25 Гб памяти, то Windows радостно уходит в своп, делая работу с приложением просто невозможной. Если указать меньший предел для кучи, то до свопа не доходт и сборщик мусора всё отлично очищает. Но, к сожалению, при этом есть вероятность, что какая-нибудь огромная фотография просто не влезет в ограниченный объём памяти и мы получим OutOfMemory, хотя на компьютере может и 4 Гб памяти быть установлено. Что делать? -------------------- Да. Именно так. |
|||
|
||||
| LSD |
|
|||
![]() Leprechaun Software Developer ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 15718 Регистрация: 24.3.2004 Где: Dublin Репутация: 210 Всего: 538 |
Если это не сервер и кратковременная заморозка приложения не страша, периодически вызывай System.gc(). Если JVM запущена не в серверном режиме, то память будет отдаваться.
Tuning Garbage Collection with the 5.0 Java Virtual Machine. -------------------- Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it. |
|||
|
||||
| COVD |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1655 Регистрация: 26.7.2005 Репутация: 17 Всего: 43 |
Возможно, это зависит от типа gc. У меня Xmx = 256 (Xms не задана), но приложение крутится с текущей памятью ~ 5, и дефолтный gc радостно чистит, о чем сообщает в лог. Другое дело, если понадобится больше памяти, то потом JVM под виндоуз врядли отдаст в систему освободившуюся память. На Солярисе отдает. Это сообщение отредактировал(а) COVD - 27.5.2008, 18:16 |
|||
|
||||
| Дрон |
|
|||
![]() Java-ненавистник :) ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3179 Регистрация: 29.12.2002 Где: Санкт-Петербург Репутация: 6 Всего: 93 |
Да я вот уже подумал завести отдельный поток, который только тем и будет заниматься, что следить за состоянием приложения (занято ли оно чем-то полезным) и периодически дёргать сборщих мусора. Только мне казалось, что он сам должен этим заниматься. Добавлено через 10 минут и 21 секунду
Вот это мне и не понятно. Ладно бы он нормально чистил память, тогда я и на ограничение Xmx я не жаловался, но почему-то вместо это получается только постоянный жор, пока не упрётся в предел. И мне даже не очень-то и нужно, чтобы память обратно в систему отдавалась -- мне гораздо важнее, чтобы куча JVM не росла без надобности. Это сообщение отредактировал(а) Дрон - 27.5.2008, 18:20 -------------------- Да. Именно так. |
|||
|
||||
| powerOn |
|
|||
![]() software saboteur ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 4367 Регистрация: 7.10.2005 Репутация: 47 Всего: 159 |
||||
|
||||
| COVD |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1655 Регистрация: 26.7.2005 Репутация: 17 Всего: 43 |
Это легко проверяется активацией лога gc. Например, указанием параметра JVM "-Xloggc:" . В консоль тогда будут выдаваться сообщения о запусках gc. Если gc запускается, но убрать ничего не может, значит "утечка" памяти, надо код анализировать. Это сообщение отредактировал(а) COVD - 27.5.2008, 18:46 |
|||
|
||||
| Дрон |
|
|||
![]() Java-ненавистник :) ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3179 Регистрация: 29.12.2002 Где: Санкт-Петербург Репутация: 6 Всего: 93 |
Спасибо. Попробуем. Однако я сомневаюсь в том что проблема в коде -- ведь когда я уменьшаю max heap, например, до 700 мегабайт, то у меня приложение продолжает отлично работать освобождая память от старых фотографий по мере загрузки новых. Значит проблем с утечкой быть не должно. Это сообщение отредактировал(а) Дрон - 27.5.2008, 18:52 -------------------- Да. Именно так. |
|||
|
||||
| LSD |
|
|||
![]() Leprechaun Software Developer ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 15718 Регистрация: 24.3.2004 Где: Dublin Репутация: 210 Всего: 538 |
Какую JVM запускаешь, клиентскую или серверную?
-------------------- Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it. |
|||
|
||||
| Дрон |
|
|||
![]() Java-ненавистник :) ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3179 Регистрация: 29.12.2002 Где: Санкт-Петербург Репутация: 6 Всего: 93 |
Клиентскую. Из JDK к 5-й Java, на 6-й ещё подробно не экспериментировал. Из всех параметров, что я передаю -- только установки памяти: -Xms128m -Xmx1024m. Надо действительно попробовать включить лог GC. Мне тоже кажется, что в нормальных условиях не должно быть такого неконтролируемого роста памяти. Может дело ещё в каких-то особенностях моей программы. Вот такой вопрос: если я буду, например, в цикле грузить большие картинки, сразу же "забывая" (т.е. не сохраняя ссылку) полученный результат, то память должна расти до предела или gc должен регулярно освобождать большой объём ненужных данных? Это сообщение отредактировал(а) Дрон - 27.5.2008, 19:08 -------------------- Да. Именно так. |
|||
|
||||
| Дрон |
|
|||
![]() Java-ненавистник :) ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3179 Регистрация: 29.12.2002 Где: Санкт-Петербург Репутация: 6 Всего: 93 |
Сделал логи и разобрался. Мой изначальный вывод отчасти подтверждается -- память освобождается только когда становится совсем нечего больше кушать. Причём освобождается весьма радикально -- сразу почти весь гигабайт срезала, но размер VM в диспетчере задач остался тот же:
Обратите внимание на огромный перерыв между двумя последними -- система ушла в глубокий своп и практически не отвечала несмотря на то, что память уже была очищена. Я теперь уже понял, что в тестируемой версии этого и стоило ожидать -- картинки кэшируются через SoftReference, которые живут до тех пор, пока не потребуется память. Проблема в том, что такое поведение, как мне кажется, наблюдалось ещё когда я даже не знал что такое SoftReference. Надо больше экспериментов. Если же дело только в SoftReference, то никаких проблем, это легко исправить -- надо самому контролировать свободную память и очищать кэш, при её отсутствии. Вывод такой -- по воле создателей виртуальной машины GC старается как можно меньше работать, и ему даже наплевать, что программа становится практически неработоспособна из-за отсутствия памяти Раз уж особенность JVM состоит в том, что у неё есть искуственное ограничение максимального объёма кучи, то я бы ещё предпочёл иметь возможность указать промежуточный параметр -- например 512 мегабайт, которые превышать не желательно. И чтобы GC старался их не превышать, если это возможно. Но раз такого параметра нет, то надо делать как-то вручную, а поскольку в Java нельзя узнать объём физической памяти, то на машинам с её недостатком будет работать очень плохо, а с избытком не будет использовать все возможности. Эх... Ну и, кстати, не я один сильно озабочен этой проблемой: http://bugs.sun.com/view_bug.do?bug_id=4408373 Этому "багу" уже больше семи лет. Это сообщение отредактировал(а) Дрон - 27.5.2008, 22:49 -------------------- Да. Именно так. |
|||
|
||||
| LSD |
|
||||
![]() Leprechaun Software Developer ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 15718 Регистрация: 24.3.2004 Где: Dublin Репутация: 210 Всего: 538 |
Память системе возвращается, но после принудительного вызова сборщика мусора:
-------------------- Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it. |
||||
|
|||||
| Дрон |
|
|||
![]() Java-ненавистник :) ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3179 Регистрация: 29.12.2002 Где: Санкт-Петербург Репутация: 6 Всего: 93 |
Да, к этому я и пришёл. Сделал свой кэш самоочищащющимся после достижения определённого размера в памяти (правда память там оценивается весьма условно, но вроде близко к истине), но принудительный вызов сборщика мусора всё равно нужен -- даже когда я убираю все ссылки, память не торопится очищаться (ну и ладно), а продолжает расти по мере появления новых данных (вот это плохо). В общем, сейчас у меня программа настроена так: максимальный объём 1 Гигабайт, но внутренний кэш программно ограничен 300 мегабайтами. И это меня более-менее устраивает -- в этот кэш влезет порядка 10 картинок, при этом в случае крайней необходимости программа может взять достаточно много памяти, а по ходу нормальной работы не будет разжираться. С другой стороны это я фактически ориентируюсь на худший случай, а вот если на машине установлено, например, 4 Гигабайта памяти, то я предпочёл бы иметь гораздо больший кэш. Но похоже, что это принципиальная проблема в Java. LSD, спасибо. Это сообщение отредактировал(а) Дрон - 28.5.2008, 13:52 -------------------- Да. Именно так. |
|||
|
||||
| w1nd |
|
|||
![]() Вертилятор ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1077 Регистрация: 22.3.2006 Где: Москва Репутация: 20 Всего: 54 |
Моя практика показывает, что для идеального поведения GC ему следует помогать, обнуляя ссылки вручную и не допуская возникновения перекрёстных ссылок в дохлых объектах.
-------------------- ![]() ![]() |
|||
|
||||
| Platon |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1801 Регистрация: 25.4.2006 Репутация: 16 Всего: 40 |
w1nd, вот это интересно. Если какая-нибудь брошюрка-руководство в каких случаях стоит вручную обнулять (один случай выявили: про перекрестные ссылки).
Ведь не буду же я, кодируя очередной метод класса, в его конце обнулять все локальные объекты, которые я создал в процессе работы метода. |
|||
|
||||
| w1nd |
|
|||
![]() Вертилятор ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1077 Регистрация: 22.3.2006 Где: Москва Репутация: 20 Всего: 54 |
Дык нужные места нужно выяснять, вооружившись профайлером. Обычно в визуальных компонентах бякость случается. Это сообщение отредактировал(а) w1nd - 29.5.2008, 10:35 -------------------- ![]() ![]() |
|||
|
||||
![]()
|
| Правила форума "Java" | |
|
|
Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | Java: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |