Является ли объединение объектов устаревшей техникой?

62

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

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

Хотя недавно я прочитал что-то совершенно новое (и нелогичное?) Для меня.

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

Я прочитал это в книге: Java Concurrency in Practice

Теперь я начинаю думать, что я что-то здесь неправильно понимаю, так как в первой части книги рекомендуется использовать Executorsэто повторное использование Threadвместо создания новых экземпляров.

Итак, стал ли пул объектов устаревшим в наши дни?

user10326
источник

Ответы:

72

Он не рекомендуется в качестве общего метода, потому что, как вы заметили, создание и уничтожение недолговечных объектов как таковых (например, выделение памяти и сборщик мусора) чрезвычайно дешевы в современных JVM. Поэтому использование рукописного пула объектов для обычных объектов, скорее всего, медленнее, сложнее и более подвержено ошибкам, чем обычное new. *

Однако он по-прежнему используется для специальных объектов, создание которых относительно дорого, таких как подключения к БД / сети, потоки и т. Д.

* Однажды мне пришлось повысить производительность сканирующего Java-приложения. Расследование обнаружило попытку использовать пул объектов для выделения миллионов объектов ... и умный парень, который написал его, использовал единую глобальную блокировку, чтобы сделать его потокобезопасным. Замена пула равниной newсделала приложение в 30 раз быстрее.

Петер Тёрёк
источник
1
Итак, как можно решить, является ли создание объекта слишком дорогим?
user10326
3
Если объект потребляет ресурсы операционной системы (потоки, ввод-вывод, общая память и т. Д.)
Кевин Клайн
13
@ user10326, по измерению :-) Если создание ваших объектов занимает слишком много времени и / или они связаны с каким-то особым, потенциально ограниченным ресурсом, не связанным с памятью, вы можете рассмотреть возможность объединения.
Петер Тёрёк
8
@ user10326, IMO в более чем 95% случаев, приведенные выше критерии позволяют легко решить, нужен ли вам пул объектов. (Более того, почти во всех случаях, когда требуется пул, вы, скорее всего, будете использовать существующую библиотеку / инфраструктуру, в которой, вероятно, уже реализован пул объектов.) В остальном все еще легко скрыть создание объекта, например, фабрика, которая может быть позже переопределена в зависимости от того, что вы считаете нужным.
Петер Тёрёк
2
Очень важный момент, высказанный @Peter Torok: многие фреймворки и библиотеки реализуют пул для вас, ВСЕГДА убедитесь, что вы еще не используете библиотеку из пула, прежде чем внедрять свою собственную.
Хроманко
36

Ответ на конкретный вопрос: «Является ли объединение объектов устаревшей техникой?» является:

Нет. Пул объектов широко используется в определенных местах - пул потоков, пул соединений с базой данных и т. Д.

Создание общего объекта никогда не было медленным процессом. Сам по себе пул потребляет ресурсы - память и вычислительную мощность. Любая оптимизация - это компромисс.

Правило таково:

Преждевременная оптимизация - это зло !!!

Но когда данная оптимизация преждевременна?

Преждевременная оптимизация - это любая оптимизация, выполненная до того, как вы обнаружите узкое место с помощью тщательного профилирования .

Борис Янков
источник
2
На самом деле. ОП сказал: «Я всегда стараюсь использовать его как можно больше» - это проблема, ИМО.
nerdytenor
@ Борис, то есть, согласно твоему второму предложению, мы не должны возражать против пулов соединений и потоков, пока мы не обнаружим их как узкое место с помощью профилирования?
Pacerier
1
@Pac Некоторые результаты профилирования не нуждаются в постоянном повторном измерении :-)
Дэвид Баллок
9

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

Иер
источник
1
И я хотел бы добавить, что это хорошая идея - избегать GC, когда объекты достаточно долговечны, чтобы переместиться в старшее поколение.
Zan Lynx
8

Мера

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

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

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

Мартейн Вербург
источник
3
«пусть JVM сначала немного прогреется», - я помню, когда единственным, что нужно было «подогреть», был монитор. Ой, все новое снова старое.
kylben
Единственное, что мне нужно, чтобы согреться, это кофе!
Разочарован
@Marijn, как ты позволяешь ему "прогреваться"?
Pacerier
Обратитесь к JMH Framework за подробным объяснением ( openjdk.java.net/projects/code-tools/jmh ), но в основном вы должны дать JVM шанс JIT вашего кода, запустить GC перед тестом и так далее.
Мартейн Вербург,
8

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

Зависит от контекста.


источник
1
Отличный ответ и убедительно. Я бы добавил (возможно, как звездочку?), Что утверждение «24 байта» относится к 4 экземплярам 4-байтовых операций с плавающей запятой (16 байтов), плюс 4 байта для ссылки на объект, плюс 4 байта для ссылки на блокировку. Это точные накладные расходы, которые устраняет ваш дизайн.
strickli
5

Я не знаю, есть ли изменение тренда здесь , но его , безусловно , будет так , что это зависит . Если ваш Java-класс управляет внешним ресурсом, таким как RMI-соединение или загрузка файла ресурса и т. Д., То, конечно, затраты на создание экземпляра объекта все еще могут быть высокими (хотя эти ресурсы уже могут быть объединены для вас!). Как общая практика, я бы согласился с книгой.

Джереми
источник
Ну, теперь я не знаю. Потому что даже в этом случае вы описываете, какой (до прочтения) я бы определенно использовал пул, у меня также были бы накладные расходы. 1) Новые конструкции для обработки пула. 2) Синхронизация для получения / освобождения объекта. из пула 3) поддержание пула и т. д. Итак, теперь я думаю, что, возможно, нет никакого варианта использования, который был бы полезен, за исключением, например, кэширования сокета вместо того, чтобы каждый раз открывать новый для подключения к серверу. И этот случай из-за сети
Затраты на
@ user10326 Да, именно так. Я считаю, что открытие сокета является частью накладных расходов на создание экземпляров, если задача класса - сделать это, и он должен быть инициализирован в конструкторе, тогда вас интересуют задержки и IO.
Джереми