2012-03-02 4 views
6

У меня есть приложение, которое работает в значительной степени со многими настраиваемыми объектами, которые создаются внутри методов и никогда не нуждаются в них. Вся структура (на мой взгляд) очень хорошая объектно-ориентированная и использует Службы, Утилиты и DI-модель.Как улучшить приложение, чтобы избежать проблем с кучей пространства

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

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

Что-то вроде «не создавайте объекты в циклах, создавайте их перед циклом и переписывайте их внутри» и сортировки.

+0

Я думаю, что если бы вы могли опубликовать некоторые из ваших методов (по крайней мере, в структуре), это было бы намного проще. см. также http://stackoverflow.com/q/627784/1163434 – gawicks

ответ

2

Я бы начал с профилирования вашего приложения и поиска горячих точек памяти с помощью jvisualvm (часть JDK). Это даст вам представление о том, насколько велики ваши объекты и какие вызовы методов приводят к высокому использованию памяти. Он также расскажет вам, как долго ваши объекты обходятся в памяти, что, как правило, является хорошей отправной точкой, поскольку вы хотите уменьшить масштаб, чтобы быть как можно короче.

Следующий шаг - выявить общие черты ваших объектов либо путем уточнения дизайна, либо путем реализации кеша. Если вы загружаете данные из фиксированного хранилища, вы можете использовать softreferences, так как JVM заканчивается из кучи, эти объекты будут GCed (если вы вносите изменения в эти объекты, вам, очевидно, нужно будет их перенести, прежде чем удалять жесткую ссылку). Затем, если они понадобятся снова, вашему приложению просто нужно будет перезагрузить их из хранилища резервных копий (DB, файлы или что-то еще).

Убедитесь, что вы знаете, как работает GC и понять ваши ссылки на объекты:

  • Сильные/Прямые
  • Мягкие
  • Слабый
  • Phantom

Вот несколько хороших статей которые объясняют ссылки и GC:

http://www.java-tips.org/java-se-tips/java.util/using-weakhashmap-for-listener-lists.html

http://pawlan.com/monica/articles/refobjs/

http://www.kdgregory.com/index.php?page=java.refobj

+1

Спасибо за ссылки! Очень полезные программы. –

0

Устранение любых ссылок на объекты, как только объект больше не нужен? Как только объект больше не ссылается на него, GC может его собрать, но я предполагаю, что вы уже это знали. GC может работать также и на неопубликованном графике объектов (если A имеет единственную ссылку на B и больше нет ссылки на A, тогда можно собрать A и B).

Для вызова системы System.gc() практически бессмысленно, поскольку если JVM требуется больше памяти, он сделает это самостоятельно и затем использует освобожденную память. Если он не может освободить больше памяти, тогда вы столкнетесь с OOME.

Теперь размер кучи по умолчанию не такой большой, и поэтому довольно часто требуется больше размера кучи.

Создание объектов в цикле не является особенно плохим образцом, и во многих случаях это весьма актуально. То, что следует избегать, - это повторить экземпляр одного объекта в цикле. Как правило, конкатенации строк следует избегать в циклах и заменить на StringBuilder, созданный вне цикла, поскольку он намного менее эффективен с точки зрения производительности, но не с точки зрения памяти.

Не уверен, что я действительно отвечаю на ваш вопрос.

4

Самый важный совет, который я могу дать вам такое же, как с любым вопросом производительности:

Profile, улучшения, повторите

Используйте профайлер (например VisualVM), чтобы найти, где потребляется наибольший объем памяти. Улучшите свой код, сначала снимите утечку памяти, а затем уменьшите потребление памяти в целом. Повторите этот процесс, пока вы не удовлетворитесь качеством и эффективностью вашего кода.

EDIT:

Несколько ухищрения:

  • Доля объектов вместо дублирования, когда это возможно.

  • Остерегайтесь классов Java-классов (т. Е. Различных версий Collection<T> и Map<K,V>). В зависимости от того, что вы храните и какую коллекцию используете, вы можете легко increase your memory consumption by an order of magnitude, не ожидая этого.

  • Хотя Java не имеет (как правило,) утечки памяти в том же смысле, что и в C, код Java часто имеет проблему с объектами, которые сохраняются в живых до истечения срока их действия.

    Чтобы избежать этого, ограничьте объем своих ссылок как можно больше или установите их на null, когда вы закончите с этим объектом. Примечание: не делайте этого с помощью null-setting, особенно в тривиальных методах, которые, как ожидается, скоро вернутся.

    Самое главное: убедитесь, что вы удалили объект из любых коллекций, которые он мог бы ввести, когда вы закончите с ним. Не делать этого - хороший рецепт для OutOfMemoryError - и самая распространенная причина того, что люди называют утечку памяти в мире Java.

+0

+1: Я бы также рассмотрел коммерческий профайлер, если VisualVM недостаточно. Я использую YourKit. –

5

Некоторые пункты:

  • Там нет ничего принципиально плохого в увеличении пространства кучи. Различные приложения имеют разные требования.
  • Используйте профайлер, чтобы узнать, что на самом деле происходит. Например здесь вы можете найти кучу анализатор: MAT
  • Когда вы узнали, что экземпляры определенного класса ответственны за 80% потребление кучи:
    • пытается найти обычно общий набор переменных с одинаковыми значениями. Это кандидаты, которые могут быть одним объектом, который может использоваться несколькими объектами.
    • Проверьте, особенно вы храните некоторую ссылку на относительно большой граф объектов для переменной, которая живет намного дольше, чем ваши циклы (локальные переменные потребляют стек).
    • Пусть ссылки выходят за рамки как можно быстрее.
    • Если вы используете внутренние классы, проверьте те, которые не являются статическими, поскольку нестатический внутренний класс содержит ссылку на содержащий объект.
+0

Мне очень нравятся ваши 4 подпункта (+1) – DaveFar

+2

+1 для ссылки на внутренние классы. У них довольно много подводных камней, о которых большинство людей не знают ... – thkala

0

Во-первых, я бы перепроверить свой проект, ориентируясь на необходимой верхней сложности (Landau/Big O notation).

Во-вторых, я бы прочитал Josh Bloch's Effective Java, Item 6 (Исключите ссылки устаревшие объекта), чтобы получить некоторые подсказки о

  • частые причины для «утечки памяти»
  • , а используя наименьший объем возможного затем аннулируя больше не необходимые объекты
  • пулы для кеширования и хранения.

В-третьих, если вы все еще есть исключения ООМ, я бы следовать Mikko's advises.