Коллега сказал мне, что в Java создание объекта является самой дорогой операцией, которую вы можете выполнить. Поэтому я могу только заключить, чтобы создать как можно меньше объектов.
Кажется, это несколько противоречит цели объектно-ориентированного программирования. Если мы не создаем объекты, то мы просто пишем один длинный класс класса C для оптимизации?
Ответы:
Ваш коллега понятия не имеет, о чем они говорят.
Ваша самая дорогая операция будет слушать их . Они потратили впустую ваше время, неправильно направляя вас к информации, которая устарела более чем на десятилетие (на дату первоначального опубликования этого ответа), а также к тому, что вам приходилось тратить время на публикацию здесь и исследование Интернета на предмет правды.
Надеюсь, они просто невежественно отрыгивают то, что слышали или читали более десяти лет назад, и не знают ничего лучшего. В качестве подозреваемого я бы также взял все, что они говорят, это должно быть хорошо известной ошибкой любого, кто в любом случае идет в ногу со временем.
Все является объектом (кроме
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 даже сейчас на тестах, чувствительных к вычислениям.
источник
_alloca
амортизированный.new
ключевое слово в точке доступа. Я видел , что люди используютnew ImageIcon(Image)
вpaint()
способе объектов Свинга, который является довольно дорогим и делают весь пользовательский интерфейс супер вялым. Так что это не черно-белый ответ, подумайте, прежде чем что-new
то использовать .Итог: не ставьте под угрозу свой дизайн, чтобы использовать ярлыки для создания объектов. Не создавайте объекты без необходимости. Если это целесообразно, проектируйте, чтобы избежать лишних операций (любого рода).
Вопреки большинству ответов - да, распределение объектов связано с затратами. Это низкая стоимость, но вы должны избегать создания ненужных объектов. То же самое, что вы должны избегать ненужного в вашем коде. Большие графы объектов делают GC медленнее, предполагают более длительное время выполнения, так как вы, вероятно, будете иметь больше вызовов методов, инициируете больше пропусков кэша ЦП и увеличиваете вероятность того, что ваш процесс будет перенесен на диск в случаях низкого ОЗУ.
Прежде чем кто-то расскажет об этом как о крайнем случае - я профилировал приложения, которые перед оптимизацией создали 20+ МБ объектов для обработки ~ 50 строк данных. Это хорошо при тестировании, пока вы не масштабируете до ста запросов в минуту, и вдруг вы создаете 2 ГБ данных в минуту. Если вы хотите выполнить 20 запросов в секунду, вы создаете 400 МБ объектов, а затем выбрасываете их. 20 запросов в секунду - это ничтожно мало для достойного сервера.
источник
while(something) { byte[] buffer = new byte[10240]; ... readIntoBuffer(buffer); ...
что может быть расточительным по сравнению, например, сbyte[] buffer = new byte[10240]; while(something) { ... readIntoBuffer(buffer); ...
.На самом деле, благодаря стратегиям управления памятью, которые делает возможным использование языка Java (или любого другого управляемого языка), создание объекта представляет собой нечто большее, чем увеличение указателя в блоке памяти, называемом молодым поколением. Это намного быстрее, чем C, где поиск свободной памяти должен быть сделан.
Другая часть стоимости - уничтожение объектов, но ее трудно сравнить с C. Стоимость коллекции основана на количестве объектов, сохраненных в долгосрочной перспективе, но частота коллекций зависит от количества созданных объектов ... в в конце концов, это все еще намного быстрее, чем управление памятью в стиле C.
источник
Point
объект может поместиться в 2 -х регистрах общего назначения).Другие авторы справедливо отмечают, что создание объектов в Java происходит очень быстро, и что вам не следует беспокоиться об этом в любом обычном приложении Java.
Есть несколько особых ситуаций , где это хорошая идея , чтобы избежать создания объекта.
источник
В том, что говорит ваш коллега, есть доля правды. Я почтительно предложить вопрос с объектом создания на самом деле мусор коллекции . В C ++ программист может точно контролировать, как освобождается память. Программа может накапливать Crud так долго или так коротко, как она хочет. Кроме того, программа на C ++ может отбрасывать код, используя поток, отличный от того, который его создал. Таким образом, поток, работающий в данный момент, никогда не должен останавливаться для очистки.
В противоположность этому, виртуальная машина Java (JVM) периодически останавливает ваш код для восстановления неиспользуемой памяти. Большинство разработчиков Java никогда не замечают эту паузу, поскольку она обычно нечаста и очень коротка. Чем грубее вы накапливаете или чем более ограничена ваша JVM, тем чаще эти паузы. Вы можете использовать такие инструменты, как VisualVM, чтобы визуализировать этот процесс.
В последних версиях Java алгоритм настройки мусора (GC) может быть настроен . Как правило, чем короче вы хотите сделать паузы, тем дороже накладные расходы на виртуальной машине (т. Е. ЦП и память, потраченные на координацию процесса GC).
Когда это может иметь значение? Каждый раз, когда вы заботитесь о постоянных скоростях ответа менее миллисекунды, вы будете заботиться о GC. Автоматизированные торговые системы, написанные на Java, сильно настраивают JVM, чтобы минимизировать паузы. Фирмы, которые в противном случае написали бы Java, обращаются к C ++ в ситуациях, когда системы должны постоянно реагировать.
Для записи, я не оправдываю избегание объектов в целом! По умолчанию для объектно-ориентированного программирования. Изменяйте этот подход только в том случае, если GC мешает вам, и только после попытки настроить JVM на паузу на меньшее время. Хорошей книгой по настройке производительности Java является « Производительность Java » Чарли Ханта и Бину Джона.
источник
Есть один случай, когда вы можете отговорить создавать слишком много объектов в Java из-за накладных расходов - проектирование для производительности на платформе Android
Кроме этого, вышеупомянутые ответы верны.
источник
GC настроен на многие недолговечные объекты
тем не менее, если вы можете тривиально уменьшить распределение объектов, вы должны
Одним из примеров будет построение строки в цикле, наивный способ будет
который создает новый
String
объект для каждой+=
операции (плюс aStringBuilder
и новый базовый массив char)Вы можете легко переписать это в:
этот шаблон (неизменный результат и локальное изменяемое промежуточное значение) может быть применен и к другим вещам
но кроме этого вы должны подтянуть профилировщик, чтобы найти реальное узкое место, а не гоняться за призраками
источник
StringBuilder
подходе является заранее размеромStringBuilder
так , что он никогда не должен перераспределять основной массив сStringBuilder(int)
конструктором. Это делает его единым распределением, а не1+N
распределением.Джошуа Блох ( Joshua Bloch) (один из создателей платформы Java) написал в своей книге « Эффективная Java в 2001 году»:
источник
Это действительно зависит от конкретного приложения, так что это действительно трудно сказать в целом. Тем не менее, я был бы весьма удивлен, если бы создание объектов было на самом деле узким местом производительности в приложении. Даже если они медленные, преимущества стиля кода, вероятно, перевесят производительность (если это на самом деле не заметно для пользователя)
В любом случае вам даже не следует беспокоиться об этих вещах, пока вы не профилируете свой код, чтобы определить фактические узкие места производительности вместо того, чтобы гадать. До тех пор вы должны делать все, что лучше для читабельности кода, а не производительности.
источник
Я думаю, что ваш коллега, должно быть, сказал с точки зрения создания ненужного объекта. Я имею в виду, что если вы часто создаете один и тот же объект, лучше поделиться этим объектом. Даже в тех случаях, когда создание объекта является сложным и занимает больше памяти, вы можете захотеть клонировать этот объект и избежать создания этого сложного процесса создания объекта (но это зависит от ваших требований). Я думаю, что утверждение «Создание объекта стоит дорого» следует рассматривать в контексте.
Что касается требований к памяти JVM, дождитесь Java 8, вам даже не нужно указывать -Xmx, настройки метапространства позаботятся о потребности в памяти JVM и будут автоматически расти.
источник
Существует больше для создания класса, чем выделение памяти. Есть также инициализация, я не уверен, почему эта часть не покрыта всеми ответами. Обычные классы содержат некоторые переменные и выполняют некоторую форму инициализации, и это не бесплатно. В зависимости от класса он может читать файлы или выполнять любое другое количество медленных операций.
Так что просто подумайте, что делает конструктор класса, прежде чем выяснить, свободен он или нет.
источник
GC в Java на самом деле очень оптимизирован с точки зрения быстрого создания большого количества объектов. Из того, что я могу понять, они используют последовательный распределитель (самый быстрый и самый простой O (1) распределитель для запросов переменного размера) для такого типа «пакетного цикла» в пространство памяти, которое они называют «Eden space», и только если объекты сохраняются после цикла GC они перемещаются в место, где GC может собрать их один за другим.
С учетом вышесказанного, если ваши требования к производительности становятся достаточно критичными (как в случае с реальными требованиями конечных пользователей), тогда объекты несут дополнительные издержки, но я бы не стал думать об этом с точки зрения создания / размещения. Он больше связан с локальностью ссылок и дополнительным размером всех объектов в Java, что требуется для поддержки таких концепций, как отражение и динамическая диспетчеризация (
Float
больше, чемfloat
, например, в 4 раза больше на 64-битных с его требованиями к выравниванию, и массивFloat
не обязательно должен храниться смежно с тем, что я понимаю).Одной из самых привлекательных вещей, которые я когда-либо видел в Java, заставляющих меня считать ее полноправным соперником в своей области (VFX), был интерактивный многопоточный стандартный трассировщик пути (без использования кэширования освещенности, ни BDPT, ни MLS, ни чего-либо еще) в ЦП обеспечивает предварительный просмотр в реальном времени, который довольно быстро конвертируется в бесшумное изображение. Я работал с профессионалами в C ++, посвятившим свою карьеру таким вещам, с модными профилировщиками в руках, которым было трудно это делать.
Но я заглянул в исходный код, и хотя он использовал множество объектов по тривиальной цене, наиболее важные части трассировщика пути (BVH, треугольники и материалы) очень четко и преднамеренно избегали объектов в пользу больших массивов примитивных типов ( главным образом
float[]
иint[]
), что позволило использовать гораздо меньше памяти и гарантировать пространственную локальность для перехода от одногоfloat
массива к другому. Я не думаю, что это слишком умозрительно, чтобы думать, что, если автор использовал коробочные типы понравилисьFloat
там это было бы довольно дорого обходиться. Но мы говорим о наиболее важной части этого движка, и я вполне уверен, учитывая, насколько умело разработчик оптимизировал его, что он измерил это и применил эту оптимизацию очень, очень разумно, так как он с радостью использовал объекты повсюду с тривиальная стоимость его впечатляющего трассера в реальном времени.Даже в такой критически важной для меня области, как вы, вы не будете писать эффективные продукты, если вы ограничиваете себя в неважных местах. Я бы даже утверждал, что наиболее критичные к производительности поля могут привести к еще большему требованию к производительности, поскольку нам нужно все дополнительное время, которое мы можем получить, чтобы настроить те горячие точки, которые действительно важны, не тратя такое время на вещи, которые не , Как и в примере с трассировщиком пути, приведенным выше, автор умело и разумно применил такие оптимизации только к тем местам, которые действительно, действительно имели значение, и, вероятно, задним числом после измерения, и все еще с удовольствием использовали объекты повсюду.
источник
float[]
VS.Float[]
, где обработка миллиона бывших последовательно может быть относительно довольно быстрее , чем вторая.Как уже говорили, создание объектов в Java не стоит больших затрат (но я ставлю больше, чем большинство простых операций, таких как добавление и т. Д.), И вам не следует избегать этого слишком много.
Тем не менее, это все еще стоит, и иногда вы можете попытаться собрать как можно больше предметов. Но только после того, как профилирование показало, что это проблема.
Вот отличная презентация на эту тему: https://www.cs.virginia.edu/kim/publicity/pldi09tutorials/memory-efficient-java-tutorial.pdf
источник
Я сделал быстрый микробенчмарк по этому поводу и предоставил полные источники в github. Мой вывод таков: дорого или нет создание объектов - это не проблема, но постоянное создание объектов с мыслью о том, что GC позаботится о вас, заставит ваше приложение быстрее запускать процесс GC. GC - очень дорогой процесс, и лучше всего избегать его, когда это возможно, и не пытаться его подтолкнуть.
источник