Меры предосторожности, чтобы меньше использовать пространство кучи при программировании - PullRequest
0 голосов
/ 17 августа 2011

Они занимают место в куче

String : разумное использование String, попробуйте использовать в качестве локальных переменных, убедитесь, что нет строки без ссылок, и попробуйте использовать StringBuffer или StringBuilder

статический : разумное использование статического

Переменные экземпляра : попытаться объявить переменные локально, насколько это возможно

объекты : повторное использование, насколько это возможно

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

Ответы [ 5 ]

3 голосов
/ 17 августа 2011

Вы должны быть более конкретными о том, что вы пытаетесь достичь.Есть две цели, которые (в некоторых случаях) противоречивы:

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

static: разумное использование static

Это бессмысленносовет, если вы не скажете, что такое «разумное использование».

String: разумное использование String, попробуйте использовать в качестве локальных переменных, убедитесь, что нет строки без ссылок, и попробуйте использовать StringBuffer илиStringBuilder

  • Мудрое использование - бессмысленный совет;смотри выше.
  • Убедиться, что нет строк без ссылок, бессмысленно, потому что каждая строка имеет ссылку.
  • Попытка использовать локальные переменные полезна, но не всегда применима.Иногда использование статической переменной или переменной экземпляра может уменьшить количество раз, когда вы создаете новые строки.Иногда назначение промежуточной строки локальной переменной может увеличить ее время жизни.
  • Вы не должны использовать StringBuffer для сборки строк.
  • Во многих случаях использование StringBuilder в сборке строк не помогает.и просто затрудняет чтение кода.В общем случае StringBuilder следует использовать только в том случае, если вы не можете выполнить сборку строки в одном выражении.

Переменные экземпляра: попытайтесь объявить переменные локально, насколько это возможно

Обычно это здравый совет, хотя его необходимо сбалансировать с другими вещами.

объекты: повторное использование, насколько это возможно

Это плохой совет.

Повторное использование «насколько это возможно» означает пулы объектов, а пулы объектов, как правило, используют больше пространства кучи, чем если бы вы просто уронили объект и позволили ГХ восстановить его.Пулы объектов следует использовать только в том случае, если крайне важно минимизировать скорость создания объектов.Даже в этом случае вы должны быть очень осторожны, чтобы избежать:

  • утечек объектов, не возвращая их в пул
  • выдачи "грязных" объектов из пула
  • ошибокиз-за дополнительной сложности и
  • траты памяти (например, на структуры данных пула и незанятых объектов в пуле) и, следовательно, из-за более частого запуска GC.
2 голосов
/ 17 августа 2011

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

Тщательно проектируйте / выбирайте структуры данных вашей коллекции

Многие стандартные типы коллекций Java довольно требовательны к памяти.Например, ArrayList<Integer> состоит из 2 объектов для начала и дополнительного объекта для каждого элемента массива (в зависимости от того, как элементы создаются ...).Кроме того, резервный массив ArrayList может быть больше, чем нужно.Напротив, int[] состоит только из одного объекта и использует только одно 32-битное слово на элемент.

(Аналогичное сравнение может быть сделано для более сложных структур данных, особенно когда базовый тип являетсяпримитивный тип. Существуют сторонние библиотеки, которые реализуют такие вещи, например библиотеки GNU Trove.)

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

Однако, с другой стороны, это усложняет и усложняет обслуживание вашего приложения.Например:

  • Использование int[] вместо ArrayList<Integer> приводит к большему раскрытию деталей реализации и увеличению сцепления.

  • Использование массивов для представления списков переменных или неопределенных размеров сложно.

  • Множество API-интерфейсов предназначены для приема параметров List или Collection, а не параметров массива.Таким образом, вам, скорее всего, придется разрабатывать свои собственные не библиотечные версии библиотечного кода.

  • Обобщения и массивы плохо сочетаются.

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

Использовать изменяемые классы

Экземпляры таких классов, как String и BigInteger являются неизменяемыми.Это упрощает вычислительную модель, но это означает, что «изменение» чего-либо подразумевает создание новых объектов.Вы часто можете уменьшить использование памяти на:

  • , используя изменяемые версии типов;например, используя StringBuilder / StringBuffer вместо String или

  • , делая ваши собственные классы данных приложения изменяемыми, а не неизменяемыми.

Еще раз, есть обратная сторона.Изменчивые структуры данных могут привести к большей сложности;например, если ваше приложение является многопоточным, или если вам нужно иметь возможность отменить какие-либо действия для возврата или потому, что какой-то шаг не удался.Это делает ваше приложение более сложным.В некоторых случаях единственным жизнеспособным решением является копирование структуры данных, в результате чего используется больше памяти.

В итоге, хотя вы можете сэкономить пространство кучи, вы вполне можете в конечном итоге платить другими способами.И вы можете даже не сохранить память в конце.

0 голосов
/ 17 августа 2011

Кроме того, что касается строк, всегда intern() их при чтении из файла или базы данных, чтобы у вас не было дублированных массивов символов.

0 голосов
/ 17 августа 2011

Первое: измерьте, какие объекты действительно занимают больше всего места в куче: jmap -histo:live

Затем попытайтесь уменьшить пять верхних классов.Ничего более.Мера снова.Повторяйте до тех пор, пока вы не будете удовлетворены.

Если один из кандидатов HashMap или HashSet или ConcurrentHashMap: эти классы тратят кучу памяти как могут.Используйте для них альтернативы, эффективные для памяти.

0 голосов
/ 17 августа 2011

Это очень хорошо. Еще одна вещь, на которую следует обратить внимание, это правильное закрытие объектов типа Buffer, под которыми я подразумеваю Sockets, FileReaders и т. Д. Убедитесь, что вы завернули их в try finally, где в finally вы не забыли сбросить (при необходимости) и закройте соединение / буфер. Это позволяет избежать удержания случайных ресурсов, поскольку базовое соединение все еще будет активным.

...