Как сделать память вашего Java-приложения эффективной?
Как оптимизировать использование размера кучи в приложении, в котором имеется много (миллионы) долгоживущих объектов? (большой кеш, загрузка большого количества записей из БД)
- Используйте правильный тип данных
- Избегайте java.lang.String для представления других типов данных
- Избегайте дублирования объектов
- Используйте перечисления, если значения известны заранее
- Используйте пулы объектов
- String.intern() (хорошая идея?)
- Загружать / хранить только нужные вам объекты
Я ищу общее программирование или конкретные ответы на Java. Нет переключателя компилятора.
Редактировать:
Оптимизируйте представление POJO в памяти, которое может появляться в куче миллионы раз.
Случаи применения
- Загрузите огромный CSV-файл в память (преобразованный в POJO)
- Используйте Hibernate для извлечения миллионов записей из базы данных
Резюме ответов:
- Использовать шаблон веса
- Копирование при записи
- Вместо загрузки 10M объектов с 3 свойствами, более эффективно иметь 3 массива (или другую структуру данных) размером 10M? (Может быть, трудно манипулировать данными, но если у вас действительно мало памяти...)
11 ответов
Вы не говорите, какие объекты вы хотите хранить, поэтому немного сложно дать подробный совет. Однако некоторые (не исключительные) подходы в произвольном порядке:
- По возможности используйте шаблон в полулегком весе.
- Кеширование на диск. Существует множество кеш-решений для Java.
- Есть некоторые споры относительно того, является ли String.intern хорошей идеей. Смотрите здесь вопрос. String.intern() и количество споров о его пригодности.
- Используйте мягкие или слабые ссылки для хранения данных, которые вы можете восстановить / перезагрузить по требованию. Смотрите здесь, как использовать мягкие ссылки с методами кэширования.
Знание большего количества внутренних элементов и времени жизни сохраняемых объектов приведет к более подробному ответу.
Я предлагаю вам использовать профилировщик памяти, посмотреть, где используется память, и оптимизировать это. Без количественной информации вы могли бы в конечном итоге изменить вещи, которые либо не имеют никакого эффекта, либо фактически ухудшают ситуацию.
Вы можете посмотреть на изменение представления ваших данных, особенно если ваши объекты маленькие. Например, вы можете представить таблицу данных в виде серии столбцов с массивами объектов для каждого столбца, а не по одному объекту в строке. Это может сэкономить значительные накладные расходы для каждого объекта, если вам не нужно представлять отдельную строку. например, таблица с 12 столбцами и 10 000 000 строк может использовать 12 объектов (по одному на столбец), а не 10 миллионов (по одному на строку)
Обеспечьте хорошую нормализацию вашей объектной модели, не дублируйте значения.
Гм, и, если это всего лишь миллионы объектов, я думаю, я бы просто выбрал приличную 64-битную виртуальную машину и много оперативной памяти;)
Обычные "профилировщики" не сильно вам помогут, потому что вам нужен обзор всех ваших "живых" объектов. Вам нужен анализатор дампа кучи. Я рекомендую анализатор памяти Eclipse.
Проверьте наличие дублированных объектов, начиная со строк. Проверьте, можете ли вы применять шаблоны, такие как flightweight, copyonwrite, lazy initialization (Google будет вашим другом).
Посмотрите на эту презентацию, связанную здесь. Он описывает использование в памяти общих объектов Java и примитивов и помогает понять, куда уходит вся дополнительная память.
Построение Java-приложений с эффективным использованием памяти: опыт и проблемы
Вы можете просто хранить меньше объектов в памяти.:) Используйте кэш, который разливается на диск, или используйте Terracotta, чтобы кластеризовать вашу кучу (которая является виртуальной), позволяя неиспользуемым частям быть выгруженными из памяти и прозрачно возвращать их обратно.
Если у вас есть миллионы целых чисел, чисел с плавающей точкой и т. Д., Посмотрите, позволяют ли ваши алгоритмы представлять данные в массивах примитивов. Это означает меньшее количество ссылок и более низкую стоимость ЦП для каждой сборки мусора.
Я хочу добавить кое-что к пункту, который сделал Питер Алреди (не может прокомментировать свой ответ:(), всегда лучше использовать профилировщик памяти (проверьте профилировщик памяти java), чем идти по интуиции.80% времени это рутина, что мы ignore имеет некоторые проблемы в it.also классы коллекции более подвержены утечкам памяти.
1) По возможности используйте правильные типы данных
Class Person {
int age;
int status;
}
Здесь мы можем использовать следующие переменные для экономии памяти при отправке объекта Person
class Person{
short age;
byte status;
}
2) Вместо возврата нового ArrayList<>(); from вы можете использовать Collection.emptyList(), который будет содержать только один элемент вместо 10 по умолчанию;
Например,
public ArrayList getResults(){
.....
if(failedOperation)
return new ArrayList<>();
}
//Use this
public ArrayList getResults(){
if(failedOperation)
return Collections.emptyList();
}
3) По возможности перемещайте создание объектов в методах вместо статического объявления, поскольку поля объектов будут храниться в стеке, а не в куче.
4) Использование двоичных форматов, таких как protobuf,thrift,avro,messagepack, для сокращения взаимодействия вместо json или XML.
Потратьте некоторое время на ознакомление и настройку параметров командной строки виртуальной машины, особенно тех, которые касаются сбора мусора. Хотя это не изменит объем памяти, используемой вашими объектами, это может оказать значительное влияние на производительность приложений с интенсивным использованием памяти на компьютерах с большим объемом оперативной памяти.
Причудливый: держите большинство данных сжатыми в оперативной памяти. Разверните только текущий рабочий набор. Если ваши данные имеют хорошую локацию, это может работать хорошо.
Используйте лучшие структуры данных. Стандартные коллекции в Java довольно интенсивно используют память.
[что является лучшей структурой данных]
- Если вы посмотрите на источник для коллекций, то увидите, что если вы ограничите свой доступ к коллекции, вы можете сэкономить место на элемент.
- Способ выращивания коллекции не годится для больших коллекций. Слишком много копий. Для больших коллекций вам нужен некоторый блочный алгоритм, например btree.
Assign null
значение для всехvariables
которыеno longer
используемый. таким образомmake it available for Garbage collection
,De-reference the collections
как только использование закончится, иначе GC не будет сметать их.