Является ли создание объекта узким местом в Java в многопоточной среде?

Исходя из понимания из следующего:

Где находится ссылка на переменную, в стеке или в куче?

Мне было интересно, потому что все объекты создаются на общей куче. Если несколько потоков создают объекты, чтобы предотвратить повреждение данных, должна быть какая-то сериализация, которая должна происходить, чтобы предотвратить создание нескольких объектов в одних и тех же местах. Теперь с большим количеством потоков эта сериализация вызовет большое узкое место. Как Java избегает этого узкого места? Или я что-то упускаю?

Любая помощь была оценена.

Ответ 1

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

Далее читайте: как работает TLAB в Sun JVM. Azul VM использует немного другой подход (посмотрите на "Новый поток и компоновку стека" ), в статье показано довольно много трюков. JVM могут выполнять за сцены, чтобы обеспечить скорость Java в настоящее время.

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

Свободное выделение блокировки очень важно, тем более, что вопрос касается multithreaded environment. Он также позволяет создавать настоящие блокирующие алгоритмы. Даже если сам алгоритм является блокировкой, но выделение новых объектов синхронизируется, весь алгоритм эффективно синхронизируется и в конечном итоге менее масштабируется. java.util.concurrent.ConcurrentLinkedQueue, основанный на работе Магеда М. Майкла Майкла Л. Скотта - классический пример.


Что происходит, если объект ссылается на другой поток? (из-за обсуждения)

Этот объект (назовите его A) будет перемещен в некоторую зону "оставшегося в живых". Оставшаяся часть пострадавшего проверяется реже, чем области ThreadLocal. Он содержит, как и название, объекты, ссылки которых удалось убежать, или, в частности, A, удалось остаться в живых. Часть копирования (перемещения) происходит во время некоторой "безопасной точки" (безопасная точка исключает правильный код JIT'd), поэтому сборщик мусора уверен, что объект не ссылается. Обновляются ссылки на объект, освобождаются необходимые заготовки памяти и приложение (код Java). Далее прочитайте этот упрощенный сценарий.

Для самого заинтересованного читателя и, если возможно, его жевать: высокоразвитый Бесполезный алгоритм GC

Ответ 2

Нет. JVM имеет всевозможные трюки в рукавах, чтобы избежать какой-либо простой сериализации в точке "нового".

Ответ 3

Иногда. Я написал рекурсивный метод, который генерирует целочисленные перестановки и создает из них объекты. Многопоточная версия (каждая ветвь от root = task, но совпадающая длина потока, ограниченная количеством ядер) этого метода была не быстрее. И загрузка процессора не была выше. Задачи не разделяли каких-либо объектов. После того как я удалил создание объекта из обоих методов, многопоточный метод был ~ 4 раза быстрее (6 ядер) и использовал 100% CPU. В моем тестовом примере методы генерировали ~ 4500 000 перестановок, 1500 на задание. Я думаю, что TLAB не работает, потому что пространство ограничено (см. Буферы локального распределения потока).