Должны ли мы избегать создания объектов в Java?

243

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

Кажется, это несколько противоречит цели объектно-ориентированного программирования. Если мы не создаем объекты, то мы просто пишем один длинный класс класса C для оптимизации?

Slamice
источник
39
Msgstr "Создание объекта Java - самая дорогая операция, которую вы можете выполнить" . Не могли бы вы поделиться источником этого требования?
Сонго
92
И - самая дорогая операция по сравнению с чем? По сравнению с вычислением пи до 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 распределяется почти на 100% все время, пусть будет так. Свободная память кучи JVM ничего не дает, просто сидя там.

Существует неправильное представление о том, что GC освободит память для остальной части системы полезным способом, это полностью неверно!

Куча JVM не увеличивается и не сжимается, поэтому свободная память в куче JVM положительно влияет на остальную часть системы . -Xmsвыделяет ВСЕ из того, что указано при запуске, и его эвристика заключается в том, чтобы никогда не высвобождать часть этой памяти обратно в ОС для совместного использования с любыми другими процессами ОС, пока этот экземпляр JVM не завершится полностью. -Xms=1GB -Xmx=1GBвыделяет 1 ГБ ОЗУ независимо от того, сколько объектов фактически создано в любой момент времени. Существуют некоторые настройки, которые позволяют процентам памяти кучи быть освобожденными, но для всех практических целей JVM никогда не в состоянии освободить достаточно этой памяти, чтобы это когда-либо происходилопоэтому никакие другие процессы не могут освободить эту память, поэтому остальная часть системы не получает выгоды от того, что JVM Heap также свободна. RFE для этого был «принят» 29 ноября 2006 года, но с этим ничего не было сделано. Такое поведение не считается проблемой ни у кого из авторитетов.

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

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

Единственные объекты, которые сегодня нуждаются в объединении, - это объекты, которые ссылаются на конечные ресурсы, внешние по отношению к JVM; Сокеты, файлы, соединения с базой данных и т. Д. И могут быть использованы повторно. Обычные объекты не могут быть объединены в том же смысле, что и в языках, которые позволяют вам прямой доступ к ячейкам памяти. Кэширование объектов - это другое понятие, которое может или не может быть тем, что некоторые люди наивно называют объединением , эти два понятия не одно и то же, и их не следует смешивать.

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

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

Сообщество
источник
275
+1: «Ваша самая дорогая операция - это слушать их ...». Лучшее, что я слышал в течение некоторого времени.
Rjnilsson
21
@DeadMG, даже с учетом кумулятивных издержек GC, Java может быть быстрее, чем C ++ (например, из-за сжатия кучи минимизирует потери кеша для определенных структур данных).
SK-logic
13
@ SK-logic: Поскольку GC недетерминирован, в лучшем случае чрезвычайно сложно доказать это. Что касается минимизации потерь в кеше, это трудно сделать, когда каждый объект должен иметь другую косвенность, тратить пространство кеша и увеличивать время выполнения. Тем не менее, я утверждаю, что просто используя соответствующий распределитель в C ++, такой как пул объектов или область памяти, вы можете легко сопоставить или превзойти производительность сборщика мусора. Например, вы можете написать класс арены памяти, который будет работать быстрее, чем _allocaамортизированный.
DeadMG
33
Создание объектов теперь дешевле, чем раньше. Это не бесплатно, хотя. Тот, кто говорит тебе, что лжет. А ссылка на ОО-языки, опережающую С, является преувеличенным ответом тому, кто искренне пытается учиться.
Джейсон
17
Именно из-за таких ответов мы получаем дерьмовый код. Правильный ответ: создание объекта в Java - это создание объекта Java и его инициализация. Первая часть дешевая, вторая может быть очень дорогой. Люди должны всегда смотреть на то, что происходит в конструкторах, прежде чем использовать newключевое слово в точке доступа. Я видел , что люди используют new ImageIcon(Image)в paint()способе объектов Свинга, который является довольно дорогим и делают весь пользовательский интерфейс супер вялым. Так что это не черно-белый ответ, подумайте, прежде чем что- newто использовать .
qwertzguy
94

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

Вопреки большинству ответов - да, распределение объектов связано с затратами. Это низкая стоимость, но вы должны избегать создания ненужных объектов. То же самое, что вы должны избегать ненужного в вашем коде. Большие графы объектов делают GC медленнее, предполагают более длительное время выполнения, так как вы, вероятно, будете иметь больше вызовов методов, инициируете больше пропусков кэша ЦП и увеличиваете вероятность того, что ваш процесс будет перенесен на диск в случаях низкого ОЗУ.

Прежде чем кто-то расскажет об этом как о крайнем случае - я профилировал приложения, которые перед оптимизацией создали 20+ МБ объектов для обработки ~ 50 строк данных. Это хорошо при тестировании, пока вы не масштабируете до ста запросов в минуту, и вдруг вы создаете 2 ГБ данных в минуту. Если вы хотите выполнить 20 запросов в секунду, вы создаете 400 МБ объектов, а затем выбрасываете их. 20 запросов в секунду - это ничтожно мало для достойного сервера.

jasonk
источник
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 можно выполнять экранирующий анализ, что означает, что он может выделять память для объектов, которые не экранируют метод в стеке, поэтому очистка их бесплатна - сборщик мусора не должен иметь дело с этими объектами. они автоматически сбрасываются, когда кадр стека метода разматывается (когда метод возвращается).
Джеспер
4
Следующий шаг для анализа побега является «выделить» память для малого объекта чисто в регистрах (например, Pointобъект может поместиться в 2 -х регистрах общего назначения).
Иоахим Зауэр
6
@Joachim Sauer: Это то, что делается в более новых реализациях виртуальной машины HotSpot. Это называется скалярной заменой.
Someguy
1
@ Someguy: Я читал об этом некоторое время назад, как следующее, но не проверил, чтобы убедиться, что это уже сделано. Это хорошая новость, чтобы услышать, что у нас уже есть это.
Иоахим Зауэр
38

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

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

  • Когда вы пишете приложение, чувствительное к задержке, и хотите избежать GC-пауз. Чем больше объектов вы производите, тем больше GC происходит и тем больше вероятность пауз. Это может быть обоснованным фактором для игр, некоторых мультимедийных приложений, роботизированного управления, высокочастотной торговли и т. Д. Решение состоит в том, чтобы предварительно выделить все нужные вам объекты / массивы и повторно использовать их. Есть библиотеки, которые специализируются на предоставлении такого рода возможностей, например, Javolution . Но, возможно, если вы действительно заботитесь о низкой задержке, вы должны использовать C / C ++ / ассемблер, а не Java или C # :-)
  • Избежание коробочных примитивов (Double, Integer и т. Д.) Может быть очень полезной микрооптимизацией в определенных обстоятельствах. Поскольку распакованные примитивы (double, int и т. Д.) Позволяют избежать накладных расходов на объект, они намного быстрее нагружают процессор, например, числовую обработку и т. Д. Как правило, примитивные массивы работают очень хорошо в Java, поэтому вы хотите использовать их для сокращения чисел, а не любые другие виды объектов.
  • В ситуациях с ограниченной памятью вы хотите минимизировать количество (активных) созданных объектов, поскольку каждый объект несет небольшие накладные расходы (обычно 8-16 байт в зависимости от реализации JVM). В таких обстоятельствах вам следует отдавать предпочтение небольшому количеству крупных объектов или массивов для хранения ваших данных, а не большому количеству мелких объектов.
mikera
источник
3
Стоит отметить, что escape-анализ позволит хранить в стеке недолговечные (ограниченные по времени жизни) объекты; эти объекты можно бесплатно освободить ibm.com/developerworks/java/library/j-jtp09275/index.html
Ричард Тингл
1
@Richard: отличный момент - анализ побега обеспечивает очень хорошие оптимизации. Вы должны быть осторожны, полагаясь на это: это не обязательно произойдет во всех реализациях Java и при любых обстоятельствах. Таким образом, вам часто нужно тестировать, чтобы быть уверенным.
Микера
2
Кроме того, 100% правильный анализ побега эквивалентен проблеме остановки. Не полагайтесь на анализ побега в сложных ситуациях, поскольку он может дать неправильный ответ, по крайней мере, в некоторых случаях.
Жюль
Первый и последний пункты не относятся к небольшим объектам, которые быстро высвобождаются, они умирают в eden (думаю, выделение стека в C, почти бесплатно) и никогда не влияют на время GC или выделение памяти. Большинство объектов размещения в Java попадают в эту категорию и, следовательно, по существу бесплатно. Второй пункт остается в силе.
Билл К
17

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

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

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

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

Для записи, я не оправдываю избегание объектов в целом! По умолчанию для объектно-ориентированного программирования. Изменяйте этот подход только в том случае, если GC мешает вам, и только после попытки настроить JVM на паузу на меньшее время. Хорошей книгой по настройке производительности Java является « Производительность Java » Чарли Ханта и Бину Джона.

Greg
источник
10
Большинство современных JVM поддерживают лучшие алгоритмы сборки мусора, чем «останови мир». Амортизируемое время, затрачиваемое на сборку мусора, часто меньше, чем то, что тратится на явный вызов malloc / free. Также управление памятью C ++ работает в отдельном потоке?
10
Более новые версии Java от Oracle могут выполнять анализ экранирования, что означает, что объекты, не экранирующие метод, размещаются в стеке, что делает их очистку бесплатной - они автоматически освобождаются при возврате метода.
Джеспер
2
@ ThorbjørnRavnAndersen: Действительно? Вы действительно имеете в виду pause- меньше GC, или вы имеете в виду «как правило , параллельно-но-иногда-а-крошечная-разрядным задержки» GC? Я не понимаю, как сборщик мусора никогда не может приостанавливать программу, и в то же время перемещать объекты одновременно ... мне это кажется в буквальном смысле невозможным ...
Мердад
2
@ ThorbjørnRavnAndersen: Как это может «остановить мир», но никогда не «останавливать JVM»? Это не имеет смысла ...
Мердад
2
@ ThorbjørnRavnAndersen: Нет, на самом деле нет; Я просто не понимаю, что ты говоришь. Либо GC иногда ставит программу на паузу, и в этом случае она - по определению - не «без паузы», или она никогда не приостанавливает программу (следовательно, она «без паузы»), и в этом случае я не понимаю, как это соответствует вашему заявлению «он останавливает мир, когда не может идти в ногу», поскольку это может означать, что программа приостановлена ​​во время работы ГХ. Не могли бы вы объяснить, в чём дело (без пауз или нет?) И как это возможно?
Мердад
11

Есть один случай, когда вы можете отговорить создавать слишком много объектов в Java из-за накладных расходов - проектирование для производительности на платформе 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 по крайней мере удвоит текущую емкость, или, другими словами, емкость будет расти в геометрической прогрессии только при распределении log (n)
трещотка урод
6

Джошуа Блох ( Joshua Bloch) (один из создателей платформы Java) написал в своей книге « Эффективная Java в 2001 году»:

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

Энтони Ананич
источник
1
Даже с такими вещами, как сетевое соединение, важно не поддерживать объекты, выделенные GC, связанные с соединениями, а поддерживать набор соединений, которые существуют за пределами мира, управляемого GC. Есть моменты, когда объединение самих объектов может быть полезным; большинство из них проистекают из случаев, когда пара ссылок на один и тот же объект может быть семантически эквивалентна паре ссылок на идентичные, но отличающиеся объекты, но, тем не менее, имеют некоторые преимущества. Например, две ссылки на одну и ту же строку в пятьдесят тысяч символов могут быть проверены на равенство ...
суперкат
2
... намного быстрее, чем ссылки на две разные, но идентичные строки такой длины.
суперкат
5

Это действительно зависит от конкретного приложения, так что это действительно трудно сказать в целом. Тем не менее, я был бы весьма удивлен, если бы создание объектов было на самом деле узким местом производительности в приложении. Даже если они медленные, преимущества стиля кода, вероятно, перевесят производительность (если это на самом деле не заметно для пользователя)

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

Oleksi
источник
В ранних версиях Java затраты на сборщик мусора убирались из-за существенных затрат. В последних версиях Java значительно улучшены параметры GC, поэтому создание объектов редко является проблемой. Обычно веб-системы ограничены вызовами ввода-вывода во внешние системы, если вы не вычисляете что-то действительно сложное на сервере приложений как часть загрузки страницы.
Грег
3

Я думаю, что ваш коллега, должно быть, сказал с точки зрения создания ненужного объекта. Я имею в виду, что если вы часто создаете один и тот же объект, лучше поделиться этим объектом. Даже в тех случаях, когда создание объекта является сложным и занимает больше памяти, вы можете захотеть клонировать этот объект и избежать создания этого сложного процесса создания объекта (но это зависит от ваших требований). Я думаю, что утверждение «Создание объекта стоит дорого» следует рассматривать в контексте.

Что касается требований к памяти JVM, дождитесь Java 8, вам даже не нужно указывать -Xmx, настройки метапространства позаботятся о потребности в памяти JVM и будут автоматически расти.

АКС
источник
Было бы очень конструктивно, если бы люди оставляли комментарии и во время голосования за любой ответ. В конце концов, мы все здесь для того, чтобы делиться знаниями, и простое суждение без надлежащей причины не будет служить какой-либо цели.
AKS
1
Обмен стека должен иметь некоторый механизм для уведомления пользователей, которые проголосуют против любого ответа, когда комментарий будет опубликован на этот ответ.
AKS
1

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

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

Alex
источник
2
По этой причине хорошо спроектированный класс не должен выполнять тяжелую работу в своем конструкторе. Например, ваш класс чтения файлов может снизить стоимость создания экземпляра, только проверяя, существует ли его целевой файл при запуске, и откладывая любые фактические файловые операции до первого вызова метода, который требует данных из файла.
ГордонМ
2
Если дополнительные затраты перенесены в 'if (firstTime)', то воссоздание класса в цикле все еще обходится дороже, чем повторное использование класса.
Алекс
Я собирался опубликовать аналогичный ответ, и я считаю, что это правильный ответ. Так много людей ослеплены этими высказываниями, что создание объектов Java дешево, что они не понимают, что часто конструкторы или дальнейшая инициализация могут быть далеко не дешевы. Например, класс ImageIcon в Swing, даже если вы передадите ему предварительно загруженный объект Image, конструктор будет довольно дорогим. И я не согласен с @GordonM, многие классы из JDK выполняют большую часть init в конструкторе, и я думаю, что это делает код более компактным и лучше разработанным.
qwertzguy
1

GC в Java на самом деле очень оптимизирован с точки зрения быстрого создания большого количества объектов. Из того, что я могу понять, они используют последовательный распределитель (самый быстрый и самый простой O (1) распределитель для запросов переменного размера) для такого типа «пакетного цикла» в пространство памяти, которое они называют «Eden space», и только если объекты сохраняются после цикла GC они перемещаются в место, где GC может собрать их один за другим.

С учетом вышесказанного, если ваши требования к производительности становятся достаточно критичными (как в случае с реальными требованиями конечных пользователей), тогда объекты несут дополнительные издержки, но я бы не стал думать об этом с точки зрения создания / размещения. Он больше связан с локальностью ссылок и дополнительным размером всех объектов в Java, что требуется для поддержки таких концепций, как отражение и динамическая диспетчеризация ( Floatбольше, чем float, например, в 4 раза больше на 64-битных с его требованиями к выравниванию, и массив Floatне обязательно должен храниться смежно с тем, что я понимаю).

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

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

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

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

Энергия Дракона
источник
1
Ваш первый абзац находится на правильном пути. В Eden и Young Space используются копировальные аппараты с ок. 0 стоимость за мертвые предметы. Я очень рекомендую эту презентацию . Кстати, вы понимаете, что этот вопрос относится к 2012 году, верно?
JimmyJames
@JimmyJames Мне скучно, и я люблю просто просеивать вопросы, в том числе старые. Я надеюсь, что люди не против моей некромантии! :-D
Энергия Дракона
@JimmyJames Разве это больше не тот случай, когда у коробочных типов есть дополнительные требования к памяти, и не гарантируется, что они будут смежными в массиве? Я склонен думать , объекты дешевы в Java , но один случай , когда они могут быть относительно дорогими, как float[]VS. Float[], где обработка миллиона бывших последовательно может быть относительно довольно быстрее , чем вторая.
Энергия Дракона,
1
Когда я впервые начал писать здесь, я делал то же самое. Только не удивляйтесь, когда ответы на старые вопросы имеют тенденцию привлекать очень мало внимания.
JimmyJames
1
Я почти уверен, что предполагается, что коробочные типы занимают больше места, чем примитивы. Вокруг этого есть потенциальные оптимизации, но я в целом думаю, что это так, как вы описали. Гил Тене (из презентации выше) еще раз рассказал о предложении добавить специальный вид коллекции, которая обеспечила бы некоторые преимущества структур, но все еще используя объекты. Это интересная идея, я не уверен в статусе JSR. Стоимость во многом зависит от времени, на которое вы намекаете. Если вы можете не позволить вашим объектам «убежать», они даже могут быть распределены в стеке и никогда не касаться кучи.
JimmyJames
0

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

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

Вот отличная презентация на эту тему: https://www.cs.virginia.edu/kim/publicity/pldi09tutorials/memory-efficient-java-tutorial.pdf

Rkj
источник
0

Я сделал быстрый микробенчмарк по этому поводу и предоставил полные источники в github. Мой вывод таков: дорого или нет создание объектов - это не проблема, но постоянное создание объектов с мыслью о том, что GC позаботится о вас, заставит ваше приложение быстрее запускать процесс GC. GC - очень дорогой процесс, и лучше всего избегать его, когда это возможно, и не пытаться его подтолкнуть.

Архимед Траяно
источник
Похоже, это не дает ничего существенного по сравнению с замечаниями, сделанными и объясненными в предыдущих 15 ответах. Едва ли контент стоит того, чтобы столкнуться с вопросом, который был задан более 2 лет назад и получил очень подробный ответ
комнат