Чи слід уникати створення об’єктів на Java?


243

Мені сказав колега, що в Java створене об'єктів - це найдорожча операція, яку ви могли виконати. Тож я можу лише зробити висновок, щоб створити якомога менше об’єктів.

Це, здається, дещо перешкоджає меті об'єктно-орієнтованого програмування. Якщо ми не створюємо об'єкти, тоді ми просто пишемо один довгий стиль класу C для оптимізації?


39
"Створення об'єктів Java - найдорожча операція, яку ви могли виконати" . Ви хочете поділитися з джерелом цієї претензії?
Сонго

92
І - найдорожча операція порівняно з якою? Порівняно з обчисленням pi до 900 цифр або порівняно з збільшенням int?
жасонька

4
Чи могли вони говорити про певну частину конкретного створення об'єкта? Я думаю, як Apple використовує чергу для tableViewCells. Можливо, ваш колега запропонував створити декілька об’єктів і повторно їх використовувати через деяку накладну вартість, пов’язану з цими конкретними об'єктами? Тільки намагаюся розібратися, чому вони заявляють таку претензію.
Тайлер ДеВітт

3
Це одна з найсмішніших речей, яку я коли-небудь чув про програмування.)
Мерт Аккакая

22
Арифмічний теж досить дорогий; нам слід уникати обчислень, о, і запуск JVM - це дуже дорого, тому ми не повинні запускати JVM :-).
Джеймс Андерсон

Відповіді:


478

Ваш колега поняття не має, про що вони говорять.

Вашою найдорожчою операцією було б їх прослуховування . Вони витратили ваш час неправильно націливши вас на інформацію, яка застаріла більше десятиліття (станом на початкову дату була опублікована ця відповідь) , а також вам доведеться витрачати час на публікацію тут та дослідження правдивості в Інтернеті.

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

Все є об'єктом (крім primitives)

Все, окрім примітивів ( int, long, doubleтощо), є об'єктами на Java. Не можна уникнути створення об’єктів на Java.

Створення об’єктів у Java завдяки стратегіям розподілу пам'яті у більшості випадків швидше, ніж C ++, і для всіх практичних цілей порівняно з усім іншим у JVM можна вважати "безкоштовним" .

Ще наприкінці 1990-х на початку 2000-х років впровадження JVM мало певні результати у фактичному розподілі Об'єктів. Так не було принаймні з 2005 року.

Якщо ви налаштовуєтеся -Xmsна підтримку всієї пам'яті, необхідної для правильної роботи вашої програми, GC, можливо, ніколи не доведеться запускати та підмітати більшість сміття в сучасних реалізаціях GC, короткотривалі програми можуть взагалі ніколи не GC.

Він не намагається і максимізує вільний простір, який так чи інакше є червоною оселедець, але максимально збільшує продуктивність виконання. Якщо це означає, що JVM Heap майже 100% виділяється весь час, так і нехай буде. Безкоштовна купа пам’яті JVM нічого не дає тобі просто сидіти там.

Існує помилкова думка, що GC звільнить пам'ять до решти системи корисним способом, це абсолютно помилково!

Купа JVM не росте і не зменшується, так що на решту системи позитивно впливає вільна пам'ять у купі JVM . -Xmsвиділяє ВСЕ, що зазначено при запуску, і його евристичністю є те, що ніколи реально не випускати будь-яку з цієї пам'яті назад в ОС для спільного використання з будь-якими іншими процесами ОС до тих пір, поки цей примірник JVM не завершиться повністю. -Xms=1GB -Xmx=1GBвиділяє 1 Гб оперативної пам’яті незалежно від того, скільки об’єктів фактично створено в даний момент часу. Є деякі параметри, які дозволяють звільнити відсотки пам'яті купи, але для всіх практичних цілей JVM ніколи не в змозі звільнити достатню кількість цієї пам'яті, щоб це коли-небудь відбулосятому жоден з інших процесів не може повернути цю пам'ять, тому решта системи не виграє і від того, щоб JVM Heap не був безкоштовним. RFE для цього було "прийнято" 29-НОВ-2006, але з цього приводу нічого не робилося. Така поведінка не вважається занепокоєнням нікого з авторитетів.

Існує помилкова думка, що створення багатьох невеликих короткотривалих об'єктів змушує JVM робити паузи протягом тривалих періодів часу, це також помилково

Поточні алгоритми ГК фактично оптимізовані для створення багатьох безлічі невеликих об'єктів, які є короткочасними, тобто в основному це 99% евристики для об'єктів Java у кожній програмі. Спроби об’єднання об'єднань фактично зроблять JVM ефективнішим у більшості випадків.

Єдині об'єкти, які сьогодні потребують об'єднання, - це об'єкти, які посилаються на обмежені ресурси, які є зовнішніми для спільного використання; Сокети, файли, підключення до бази даних тощо, і їх можна повторно використовувати. Регулярні об'єкти не можна об'єднати в тому ж сенсі, що і в мовах, які дозволяють вам отримати прямий доступ до місць пам'яті. Кешування об'єктів - це інша концепція, і це може бути, а може і не бути тим, що деякі люди наївно називають об'єднанням , ці два поняття - це не одне і те ж і не слід їх поєднувати.

Сучасні алгоритми GC не мають такої проблеми, оскільки вони не розміщуються за графіком, вони розміщують, коли потрібна вільна пам'ять певного покоління. Якщо купа досить велика, то ніякі угоди не відбуваються досить довго, щоб викликати паузи.

Динамічні мови, орієнтовані на об'єкти, навіть зараз днями б'ють С на обчислювальних тестах.


274
+1: "Вашою найдорожчою операцією було б їх прослуховування ...". Найкраще, що я чув протягом деякого часу.
rjnilsson

21
@DeadMG, навіть при накопичувальних накладних витратах GC, Java може бути швидше, ніж C ++ (наприклад, завдяки ущільненню купи, мінімізуючи пропуски кешу для певних структур даних).
SK-логіка

13
@ SK-логіка: Оскільки GC не детермінований, вкрай важко насправді довести це. Що стосується мінімізації пропусків кеша, то важко це зробити, коли кожен об'єкт повинен мати іншу непрямість, витрачаючи кеш-пам'ять та збільшуючи час виконання. Однак я заперечую, що просто використовуючи відповідний розподільник на об’єкті пулу об’єктів або на арені пам’яті, ви можете легко співставити чи перемогти продуктивність збирача сміття. Наприклад, ви можете написати клас арени пам'яті, який буде працювати швидше, ніж _allocaамортизований.
DeadMG

33
Створення об’єктів зараз дешевше, ніж раніше. Це не безкоштовно. Той, хто каже вам, що бреше. І посилання про побиття мов OO - це перебільшена реакція на того, хто щиро намагається навчитися.
жасонька

17
Через такі відповіді ми стикаємося з хижим кодом. Правильна відповідь - створення об’єкту в Java - це і створення об'єкта Java, і ініціалізація. Перша частина дешева, друга може бути дуже дорогою. Люди завжди повинні дивитись, що відбувається в конструкторах, перш ніж використовувати newключове слово в точковому місці. Я бачив, як люди використовують new ImageIcon(Image)в paint()методі Swing об'єктів, що є досить дорогим і робить весь інтерфейс користувача дуже млявим. Тож це не чорно-біла відповідь, подумайте, перш ніж newдесь використовувати .
qwertzguy

94

Підсумок: Не робіть компроміс із дизайном, щоб приймати ярлики, створюючи об'єкти. Не уникайте створення об'єктів без потреби. Якщо це розумно, спроектуйте, щоб уникнути зайвих операцій (будь-яких видів).

Всупереч більшості відповідей - так, розподіл об'єктів DO має пов’язану вартість. Це низька вартість, але вам слід уникати створення зайвих об’єктів. Те саме, що вам слід уникати зайвого нічого у вашому коді. Великі графіки об'єктів роблять GC повільнішими, маючи на увазі більш тривалий термін виконання, оскільки у вас, ймовірно, буде більше викликів методів, запускаються більше пропусків кешу процесора та збільшується ймовірність того, що ваш процес буде замінений на диск у випадках з низькою оперативною пам’яттю.

Перед тим, як хтось розбирається, що це кращий випадок - у мене були профільовані програми, які перед оптимізацією створювали 20 + МБ об'єктів, щоб обробити ~ 50 рядків даних. Це добре в тестуванні, поки ви не масштабуєте до ста запитів в хвилину і раптом не створите 2 Гб даних в хвилину. Якщо ви хочете зробити 20 частот / с, ви створюєте 400 Мб об'єктів, а потім викидаєте їх. 20 reqs / sec є мінімальним для гідного сервера.


7
Я можу додати приклад: в деяких випадках це дійсно не має різниці в ясності коду, але може зробити більш-менш велику різницю в продуктивності: Наприклад, читаючи з потоків, не рідкість використовувати щось подібне, while(something) { byte[] buffer = new byte[10240]; ... readIntoBuffer(buffer); ...що може бути марними порівняно з напр byte[] buffer = new byte[10240]; while(something) { ... readIntoBuffer(buffer); ....
JimmyB

4
+1: Непотрібне створення об'єкта (а точніше очищення після видалення), безумовно, іноді може бути дорогим. 3D-графіка / код OpenGL в Java - це одне місце, де я бачив оптимізації, зроблені для мінімізації кількості створених об'єктів, оскільки GC може інакше спричинити хаос із вашим кадром.
Лев

1
Оце Так! 20+ Мб для обробки 50 рядків даних? Звучить божевільно. У будь-якому випадку, чи є ці об’єкти довгожителями? Тому що це має значення для GC. Якщо з іншого боку ви просто обговорюєте вимоги пам’яті , це не пов’язано з ефективністю збору сміття чи створення об’єктів ...
Андрес Ф.

1
Об'єкти недовговічні (менше 0,5 сек в загальному випадку). Цей обсяг сміття все ще впливає на продуктивність.
жасонька

2
Дякую за те, що насправді твердо стоїть на реальності, кожен, хто живе з наслідками бездумної архітектури, може дуже сподіватися.
Дж. М. Бекер

60

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

Інша частина вартості - це знищення об'єктів, але її важко порівняти з C. Вартість колекції базується на кількості об'єктів, що довго зберігаються, але частота колекцій залежить від кількості створених об'єктів ... у Зрештою, це все ще набагато швидше, ніж управління пам'яттю в стилі C.


7
+1 Незважаючи на те, що сміттєзбірник "просто працює", кожен програміст Java повинен дізнатися про покоління сміттєзбірника.
бензадо

18
Новіші версії Java можуть робити аналіз втечі, це означає, що вона може виділяти пам'ять для об'єктів, які не уникають методу на стеці, так що очищення їх вільне - сміттєзбірник не повинен мати справу з цими об'єктами вони автоматично відкидаються, коли кадр стека методу розкручується (коли метод повертається).
Jesper

4
Наступний крок для аналізу втечі є «виділити» пам'ять для малого об'єкта чисто в регістрах (наприклад, Pointоб'єкт може поміститися в 2 -х регістрах загального призначення).
Йоахім Зауер

6
@Joachim Sauer: Це саме те, що робиться в нових версіях VM HotSpot. Це називається скалярною заміною.
someguy

1
@someguy: Я читав про це деякий час тому як про чергову річ, але не слідкував, щоб перевірити, чи це вже зроблено. Відмінна новина почути, що у нас це вже є.
Йоахім Зауер

38

Інші плакати справедливо зазначають, що створення об’єктів на Java дуже швидке, і що зазвичай не варто турбуватися про це в будь-якому звичайному додатку Java.

Є кілька особливих ситуацій , де це гарна ідея , щоб уникнути створення об'єкта.

  • Коли ви пишете заявку, залежну від затримки, і хочете уникати пауз GC. Чим більше об’єктів ви виробляєте, тим більше трапляється GC і більше шансів зробити паузи. Це може бути вагомим питанням, що стосується ігор, деяких медіа-додатків, роботизованого управління, високочастотної торгівлі тощо. Рішення полягає в тому, щоб попередньо виділити всі необхідні вам об'єкти / масиви вперед і повторно їх використовувати. Є бібліотеки, які спеціалізуються на наданні такого роду можливостей, наприклад, Javolution . Але, мабуть, якщо ви дійсно піклуєтесь про низьку затримку, вам слід скористатися C / C ++ / асемблером, а не Java або C # :-)
  • Уникнення коробчатих примітивів (Double, Integer тощо) може бути дуже вигідною мікрооптимізацією за певних обставин. Оскільки безкомбіновані примітиви (подвійні, int і т. Д.) Уникають накладних витрат на об'єкт, вони набагато швидше інтенсивно працюють з процесором, як числова обробка тощо. будь-які інші види об’єктів.
  • У обмежених ситуаціях пам'яті потрібно мінімізувати кількість (активних) об’єктів, створених, оскільки кожен об'єкт має невеликі накладні витрати (як правило, 8-16 байт залежно від реалізації JVM). За таких обставин вам слід віддати перевагу невеликій кількості великих об’єктів чи масивів для зберігання своїх даних, а не великій кількості малих об’єктів.

3
Варто відзначити, що аналіз втечі дозволить зберігати короткотривалі (обмежені терміни життя) об’єкти в стеці, ці об’єкти можна розмістити безкоштовно ibm.com/developerworks/java/library/j-jtp09275/index.html
Річард Тінгл

1
@Richard: Аналіз кращого втечі дає дуже хороші оптимізації. Ви повинні бути обережні, покладаючись на це: це не гарантується у всіх реалізаціях Java та за будь-яких обставин. Тому вам часто потрібно орієнтуватися, щоб бути впевненим.
mikera

2
Також 100% правильний аналіз втечі рівнозначний проблемі зупинки. Не покладайтеся на аналіз втечі у складних ситуаціях, оскільки це, швидше за все, дасть неправильну відповідь хоча б частину часу.
Жуль

Перший і останній пункти не стосуються невеликих об'єктів, які швидко вивільняються, вони гинуть в Едені (думаю, розподіл стеку в С, майже безкоштовно) і ніколи не впливають на час GC або розподіл пам'яті. Більшість розміщення об’єктів на Java підпадає під цю категорію і тому по суті є безкоштовним. Другий пункт все ще діє.
Білл К

17

У вашому колезі є ядро ​​істини. Я з повагою пропоную проблему зі створенням об'єктів - це власне збирання сміття . У програмі C ++ програміст може точно контролювати спосіб розміщення пам'яті. Програма може накопичувати сиру так довго або так швидко, як їй подобається. Крім того, програма C ++ може скинути сиру, використовуючи інший потік, ніж той, що створив її. Таким чином, нитка, яка працює в даний час, ніколи не повинна зупинятись на очищенні.

На відміну від цього, віртуальна машина Java (JVM) періодично зупиняє ваш код, щоб повернути невикористану пам'ять. Більшість розробників Java ніколи не помічають цієї паузи, оскільки вона зазвичай нечаста і дуже коротка. Чим сильніше ви накопичуєте або тим більше обмежує ваш JVM, тим частіше ці паузи. Ви можете використовувати такі інструменти, як VisualVM, для візуалізації цього процесу.

В останніх версіях Java алгоритм збору сміття (GC) може бути налаштований . Як правило, чим коротше ви хочете робити паузи, тим дорожче накладні витрати у віртуальній машині (тобто процесор і пам'ять, витрачені на координацію процесу GC).

Коли це може мати значення? Будь-який час, коли ви піклуєтесь про постійні частоти реакцій на півмілісекунди, ви піклуєтесь про GC. Автоматизовані торгові системи, написані на Java, сильно налаштовують JVM, щоб мінімізувати паузи. Фірми, які б інакше писали Java, перетворюються на C ++ у ситуаціях, коли системам постійно доводиться високо реагувати.

Для запису я взагалі не потураю уникненню уникнення предметів! За замовчуванням об'єктно-орієнтоване програмування. Налаштуйте цей підхід лише в тому випадку, якщо GC перешкоджає вам, а потім лише після спроби налаштувати JVM на паузу на менший час. Хорошою книгою про налаштування продуктивності Java є Java Performance Чарлі Хант та Біну Джон.


10
Більшість сучасних JVM підтримують кращі алгоритми збору сміття, ніж "зупиняють світ". Амортизований час, витрачений на вивезення сміття, часто менший, ніж витрачається, явно називаючи malloc / free. Чи також управління пам'яттю C ++ працює в окремому потоці?

10
Новіші версії Java від Oracle можуть робити аналіз втечі, це означає, що об’єкти, які не уникають методу, виділяються на стек, що робить їх очищенням вільним - вони автоматично розміщуються, коли метод повертається.
Джеспер

2
@ ThorbjørnRavnAndersen: Дійсно? Ви дійсно маєте на увазі паузу без ГК, або ви маєте на увазі "звичайно-паралельне, але іноді-а-крихітне-бітове пауза" GC? Я не розумію, як GC ніколи не може призупинити програму, і все ж переміщувати об’єкти одночасно ... мені це здається абсолютно буквально неможливим ...
Мехрдад

2
@ ThorbjørnRavnAndersen: Як це може "зупинити світ", але ніколи не "призупинити JVM"? Це не має сенсу ...
Мехрдад

2
@ ThorbjørnRavnAndersen: Ні, я насправді не так; Я просто не розумію, що ти говориш. Або GC іноді призупиняє програму, і в цьому випадку вона - за визначенням - не "без пауз", або вона ніколи не призупиняє програму (отже, вона "без паузи"), і в такому випадку я не розумію, як це відповідає вашому твердженню "він зупиняє світ, коли він не може йти в ногу", оскільки це, мабуть, означає, що програма призупинена під час роботи GC. Ви б не подумали пояснити, що це за випадок (це пауза чи ні?), І як це можливо?
Мехрдад

11

Є один випадок, коли вас можуть відмовити створювати занадто багато об’єктів на Яві через накладні витрати - розробка для продуктивності на платформі Android

Окрім цього, вищезазначені відповіді справедливі.


2
Прочитайте питання ще раз. Він не вказує JVM ніде, включаючи теги. Він лише згадує Java.
Пітер Келлі

9

GC налаштований на багато нетривалих об’єктів

що сказав, якщо ви можете тривільно зменшити розподіл об'єктів, який слід

одним із прикладів буде побудова рядка в циклі, наївний спосіб

String str = "";
while(someCondition){
    //...
    str+= appendingString;
}

який створює новий Stringоб'єкт для кожної +=операції (плюс a StringBuilderта новий базовий масив char)

Ви можете легко переписати це на:

StringBuilder strB = new StringBuilder();
while(someCondition){
    //...
    strB.append(appendingString);
}
String str = strB.toString();

ця закономірність (незмінний результат та локальне змінне проміжне значення) може бути застосована і до інших речей

окрім того, ви повинні підтягнути профілера, щоб знайти справжнє вузьке місце замість того, щоб ганяти за привидами


найбільша перевага в цьому StringBuilderпідході є заздалегідь розміромStringBuilder так , що він ніколи не повинен перерозподіляти основний масив з StringBuilder(int)конструктором. Це робить його єдиним розподілом, а не 1+Nрозподілом.

2
@JarrodRoberson StringBuilder буде по крайней мере вдвічі нагрузочная або іншими словами, потужність буде зростати в геометричній прогресії тільки журнал (п) розподілів
тріскачки урод

6

Джошуа Блох (один із творців платформи Java) написав у своїй книзі « Ефективна Java» у 2001 році:

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


1
Навіть у таких речах, як мережне підключення, найважливішим є не підтримка виділених GC об'єктів, пов'язаних із з'єднаннями, а підтримка набору з'єднань, які існують поза межами керованого GC. Бувають випадки, коли об’єднання самих об’єктів може бути корисним; більшість із них випливають із випадків, коли пара посилань на один і той же об'єкт може бути семантично еквівалентна парі посилань на однакові, але відмінні об'єкти, але, тим не менш, має деякі переваги. Наприклад, дві посилання на один і той же рядок п'ятдесят тисяч символів можуть бути перевірені на рівність ...
supercat

2
... набагато швидше, ніж посилання на дві чіткі, але однакові рядки такої довжини.
supercat

5

Це дійсно залежить від конкретного застосування, тому взагалі важко сказати. Однак я був би дуже здивований, якби створення об'єктів насправді було вузьким місцем у програмі. Навіть якщо вони повільні, користь у стилі коду, ймовірно, переважатиме ефективність (якщо тільки це не помітно користувачеві)

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


У ранніх версіях Java були істотні витрати, які виникли, коли збирач сміття прибирав викинуті предмети. Останні версії Java значно покращили параметри GC, тому створення об'єктів рідко є проблемою. Зазвичай веб-системи обмежуються дзвінками вводу-виводу до зовнішніх систем, якщо ви не обчислюєте щось дійсно складне на сервері додатків у рамках завантаження сторінки.
greg

3

Я думаю, що ваш колега, мабуть, сказав з точки зору створення зайвих об'єктів. Я маю на увазі, якщо ви часто створюєте один і той же об’єкт, то краще поділитися цим об’єктом. Навіть у випадках, коли створення об'єктів є складним і займає більше пам'яті, ви можете клонувати цей об'єкт і уникати створення цього складного процесу створення об'єкта (але це залежить від вашої вимоги). Я думаю, що вислів "Створення об'єкта дорого" слід сприймати в контексті.

Що стосується вимог пам'яті JVM, зачекайте на Java 8, вам навіть не потрібно вказувати -Xmx, налаштування метапростору подбає про необхідність пам'яті JVM, і вона автоматично зростатиме.


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

1
Обмін стеками повинен мати певний механізм для сповіщення користувачів, які відмовилися від будь-якої відповіді, коли коментар розміщується на цю відповідь.
AKS

1

Створення класу більше, ніж розподіл пам’яті. Також є ініціалізація, я не впевнений, чому ця частина не охоплена усіма відповідями. Нормальні класи містять деякі змінні та виконують певну форму ініціалізації, і це не безкоштовно. Залежно від класу, він може читати файли або виконувати будь-яку іншу кількість повільних операцій.

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


2
Добре розроблений клас не повинен займатися важким підйомом у своєму конструкторі саме з цієї причини. Наприклад, ваш клас читання файлів може знизити вартість інстанції, лише підтвердивши, чи є його цільовий файл при запуску, і відклавши будь-які фактичні операції з файлом до першого виклику методу, який потребує даних з файлу.
GordonM

2
Якщо додаткова вартість перенесена на 'if (firstTime)', то відтворення класу в циклі все ж дорожче, ніж повторне використання класу.
Олексій

Я збирався опублікувати подібну відповідь, і я вважаю, що це правильна відповідь. Так багато людей засліплені висловлюваннями про те, що створення об’єктів Java дешеве, що вони не усвідомлюють, що часто конструктори або подальша ініціалізація можуть бути далеко не дешевими. Наприклад, клас ImageIcon в Swing, навіть якщо ви передаєте йому попередньо завантажений об'єкт Image, конструктор досить дорогий. І я не погоджуюся з @GordonM, багато класів з JDK виконують більшу частину init у конструкторі, і я думаю, що це робить код пісні, краще розробленим.
qwertzguy

1

GC Java насправді дуже оптимізований з точки зору швидкого створення безлічі об'єктів у режимі "сплеску". З того, що я можу зрозуміти, вони використовують послідовний розподільник (найшвидший і найпростіший розподільник O (1) для запитів змінного розміру) для такого типу "циклу розриву" в просторі пам'яті, який вони називають "Едемський простір", і лише якщо об'єкти зберігаються після циклу GC вони переміщуються до місця, де GC може збирати їх по одному.

З урахуванням сказаного, якщо ваші потреби в продуктивності стануть досить критичними (як це вимірюється реальними вимогами користувачів), то об'єкти несуть накладні витрати, але я б не думав про це настільки з точки зору створення / розподілу. Це має більше спільного з локальністю відліку та додатковим розміром всіх об'єктів на Java, як це потрібно для підтримки таких понять, як відбиття та динамічна диспетчера ( Floatбільший за float, часто щось на кшталт у 4 рази більший на 64-розрядні з його вимогами до вирівнювання та масив Floatне обов'язково гарантовано зберігається безперервно від того, що я розумію).

Одна з найбільш привабливих речей, яку я коли-небудь бачив, розроблена на Java, яка змусила мене вважати її суперником у важкій вазі в моїй галузі (VFX), - це інтерактивний багатопотоковий стандартний траєктор (не використовуючи іррадіаційного кешування, BDPT, MLS чи іншого) на процесор, що забезпечує попередній перегляд у режимі реального часу, який досить швидко перетворився на зображення без шуму. Я працював з професіоналами в C ++, присвячуючи свою кар’єру таким речам, з фантазійними профілями в руці, у яких були труднощі з цим.

Але я зазирнув до вихідного коду, і хоча він використовував безліч предметів за тривіальну ціну, найбільш критичні частини траєктора шляху (BVH, трикутники та матеріали) дуже чітко і навмисно уникали об'єктів на користь великих масивів примітивних типів ( здебільшого float[]і int[]), що дозволило використовувати набагато менше пам’яті та гарантовану просторову локальність, щоб перейти з одного floatмасиву в інший. Я не думаю, що це занадто спекулятивно, щоб вважати це, якщо автор використовував вподобані коробкиFloatтам це призвело б до досить великих витрат на його виконання. Але ми говоримо про найбільш критичну частину цього двигуна, і я впевнений, враховуючи те, наскільки вміло розробник його оптимізував, що він це виміряв і застосував цю оптимізацію дуже, дуже розумно, оскільки він із задоволенням використовував предмети скрізь тривіальна вартість для його вражаючого простежувача шляху в реальному часі.

Мені сказав колега, що в Java створене об'єктів - це найдорожча операція, яку ви могли виконати. Тож я можу лише зробити висновок, щоб створити якомога менше об’єктів.

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


1
Ваш перший абзац на правильному шляху. Еден і молодий простір використовують колекціонування копій, які мають прибл. 0 вартість мертвих предметів. Дуже рекомендую цю презентацію . Зі сторони, ви розумієте, що це питання з 2012 року, правда?
JimmyJames

@JimmyJames Мені нудно і мені подобається просто просіювати питання, включаючи старі. Я сподіваюся, що люди не проти моєї некромантичності! :-D
енергія Дракона

@JimmyJames Це вже не так, що типи коробки мають додаткові вимоги до пам'яті і не гарантується, що вони будуть суміжними в масиві? Я схильний вважати, що об’єкти є забрудненими на Яві, але один випадок, коли вони можуть бути відносно дорогими, як float[]vs. Float[], де обробка мільйона колишніх послідовно може бути відносно швидшою, ніж друга.
Енергія Дракона

1
Коли я вперше почав публікувати тут, я зробив те саме. Просто не дивуйтеся, коли відповіді на старі питання, як правило, приділяють дуже мало уваги.
JimmyJames

1
Я майже впевнений, що типи, що містять коробки, повинні використовувати більше місця, ніж примітиви. Навколо цього є потенційні оптимізації, але я взагалі думаю, це так, як ви описуєте. Гіл Тене (з викладу вище) розповідає про пропозицію додати колекцію спеціального виду, яка б забезпечила деякі переваги конструкцій, але все ще використовує об'єкти. Цікава ідея, я не впевнений у статусі JSR. Вартість багато в чому обумовлена ​​часом, на який ви натякаєте. Якщо ви не можете дозволити вашим об'єктам «втекти», вони навіть можуть бути виділені стеком і ніколи не торкатися до купи.
JimmyJames

0

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

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

Ось чудова презентація на тему: https://www.cs.virginia.edu/kim/publicity/pldi09tutorials/memory-efficient-java-tutorial.pdf


0

Я зробив швидкий мікро-орієнтир щодо цього, і я надав повні джерела в github. Я можу зробити висновок: дорого чи ні створювати об’єкти - це не проблема, але безперервне створення об'єктів із уявленням, що GC піклуватиметься про речі для вас, змусить вашу програму швидше запустити процес GC. GC - це дуже дорогий процес, і найкраще уникати цього, коли це можливо, і не намагатися його підштовхувати.


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