Чи об'єднання об'єктів застаріло?


62

Я дуже добре знайомий з концепцією об'єднання об'єктів і завжди намагаюся його максимально використовувати.

Крім того, я завжди вважав, що об'єднання об'єктів є стандартною нормою, оскільки я зауважував, що сама Java, а також інші рамки використовують об'єднання якнайбільше.

Нещодавно я прочитав щось абсолютно нове (і контрінтуїтивне?).

Таке об'єднання насправді погіршує продуктивність програми, особливо в паралельних програмах, і бажано newзамість цього інстанціювати об'єкти, оскільки в нових JVM інстанціфікація об'єкта дуже швидка.

Я читав це в книзі: Java Concurrency in Practice

Тепер я починаю думати, чи я щось тут не розумію, оскільки перша частина книги пропонувала використовувати Executorsце повторне використання Threadзамість створення нових примірників.

Тож чи об'єднання об'єктів тепер застаріло?

Відповіді:


72

Це застаріло як загальна методика, оскільки - як ви помітили - створення та знищення короткотривалих об'єктів як таких (тобто розподіл пам’яті та GC) є надзвичайно дешевим у сучасних JVM. Таким чином, використання рукописного пулу об’єктів для об'єктів, що виконуються на млині, швидше за все повільніше, складніше та більш схильне до помилок, ніж звичайне new. *

Він все ще використовує свої особливості для спеціальних об'єктів, створення яких порівняно дороге, як з'єднання БД / мережа, потоки тощо.

* Одного разу мені довелося покращити продуктивність скануваного додатка Java. Дослідження виявило спробу використовувати об'єктний пул для виділення мільйонів об'єктів ... і розумний хлопець, який його написав, використав єдиний глобальний замок, щоб зробити його безпечним потоком. Заміна басейну звичайним newзробила додаток у 30 разів швидшим.


1
Тож як можна вирішити, чи інстанція об'єкта занадто дорога?
користувач10326

3
Якщо об'єкт споживає ресурси операційної системи (потоки, введення-виведення, спільна пам'ять тощо)
kevin cline

13
@ user10326, за вимірюванням :-) Якщо створення ваших об'єктів займає довгий час, та / або вони пов'язані з якимось спеціальним потенційно обмеженим ресурсом, який не є пам'яттю, ви можете розглянути можливість об'єднання.
Péter Török

8
@ user10326, IMO у понад 95% випадків, вищевказані критерії дозволяють заздалегідь вирішити, чи потрібен пул об’єктів. (Більше того, майже у всіх випадках, коли потрібен пул, ви, швидше за все, використовуватимете наявну бібліотеку / рамку, яка, ймовірно, вже об'єднана для вас об'єктним пулом.) Для решти, все ще легко приховати створення об’єктів, наприклад фабрика, яку згодом можна буде повторно доповнити будь-яким способом.
Péter Török

2
Дуже важливий момент, який зробив @Peter Torok: багато фреймворків та бібліотек реалізують об'єднання для вас, ЗАВЖДИ переконайтесь, що ви вже не використовуєте об'єднану бібліотеку, перш ніж реалізувати власну.
hromanko

36

Відповідь на конкретне питання: "Чи об'єднання об'єктів застаріла техніка?" є:

Ні. Об'єднання об'єднань широко використовується в конкретних місцях - об'єднання потоків, об'єднання баз даних тощо.

Загальне створення об'єктів ніколи не було повільним процесом. Об'єднання саме по собі споживає ресурси - пам'ять і потужність обробки. Будь-яка оптимізація є компромісом.

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

Передчасна оптимізація - це зло !!!

Але коли дана оптимізація передчасна?

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


2
Справді. ОП сказала: "Я завжди намагаюся використовувати це якомога більше" - це проблема, ІМО.
nerdytenor

@Boris, Отже, згідно з вашим другим реченням, ми не повинні заперечувати об’єднання та потоки пулу, поки ми не розкриємо їх як вузьке місце за допомогою профілювання?
Печер'є

1
@Pac Деякі результати профілювання не потребують постійного повторного вимірювання :-)
Девід Баллок

9

У ситуаціях, коли ви хочете повністю уникнути збирання сміття, я думаю, що об'єднання об'єктів є єдиною життєздатною альтернативою. Так що ні, це абсолютно не є устареною технікою.


1
І я додам, що це гарна ідея уникати GC, коли об’єкти є досить довговічними, щоб вони перейшли в старше покоління.
Zan Lynx

8

Виміряйте

Це повністю залежить від вашої справи використання, розміру ваших об'єктів, вашого JVM, ваших параметрів JVM, GC, який ви ввімкнули, і цілого ряду інших факторів.

Коротше кажучи: виміряйте його раніше і виміряйте після. Якщо припустити, що ви використовуєте рамку об'єднання об'єктів (як, наприклад, від Apache), то не слід занадто болісно обмінюватися між реалізаціями.

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


3
"нехай JVM трохи прогріється спочатку", - я пам'ятаю, коли єдине, що довелося "розігріти" - це монітор. Ой, все нове знову старе.
kylben

Єдине, що мені потрібно зігріти - це кава!
Розчарований

@Marijn, як ти даєш їй «зігрітися»?
Pacerier

Повні пояснення див. У Структурі JMH ( 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

@ user10326 Так. Я бачу відкриття сокета як частина екземпляра накладних витрат, якщо завдання класу це зробити, і його необхідно ініціалізувати в конструкторі, то затримка та наслідки введення-виводу - це те, про що ти маєш справу.
Джеремі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.