Стоимость использования слабых ссылок в Java
Кто-нибудь исследовал затраты времени выполнения, связанные с созданием и сборкой мусора Java WeakReference объектов? Существуют ли какие-либо проблемы с производительностью (например, конкуренция) для многопоточных приложений?
EDIT: Очевидно, что фактический ответ будет зависящим от JVM, но общие наблюдения также приветствуются.
РЕДАКТИРОВАТЬ 2: Если кто-то сделал некоторый бенчмаркинг производительности или может указать на некоторые результаты бенчмаркинга, это было бы идеально. (Извините, но щедрость истекло...)
Ответы
Ответ 1
WeakReferences оказывают негативное влияние на сборщик мусора CMS. Насколько я могу видеть из поведения нашего сервера, это влияет на время параллельного замечания. На этом этапе все потоки приложений прекращаются, поэтому это крайне нежелательно. Поэтому вам нужно быть осторожным с WeakReferences.
Ответ 2
Я реализовал сборщик мусора Java один раз, поэтому все, что я смог выполнить, - это (слабая) нижняя граница того, что возможно.
В моей реализации есть небольшое постоянное количество дополнительных накладных расходов для каждой слабой ссылки, когда она посещается во время сбора мусора.
Итак, результат: я бы не стал беспокоиться об этом, это не большая проблема, если вы не используете зиллионы слабых ссылок.
Самое главное, что стоимость пропорциональна количеству слабых ссылок, а не размер общей кучи.
Однако, чтобы не сказать, что сборщик мусора, который поддерживает слабые ссылки, будет таким же быстрым, как тот, который этого не делает. Предполагаемый вопрос здесь заключается в том, что Java поддерживает слабые ссылки, каковы их дополнительные затраты?
Шахта была простой "стоп-миром" маркой/сборщиком мусора. Во время сбора мусора он делает определение для каждого объекта, жив ли он или нет, и устанавливает бит LIVE
в заголовок объекта. Затем он проходит и освобождает все неживые объекты.
Чтобы обрабатывать слабые ссылки, вы просто добавляете следующее:
- Игнорировать слабые ссылки при установке битов
LIVE
(т.е. они не вызывают бит LIVE
на указанном объекте).
- На шаге развертки добавьте специальную проверку следующим образом: если объект, который вы посещаете, находится
LIVE
, а он WeakReference
, затем проверьте объект, который он слабо ссылается, и если этот объект не является LIVE
, снимите ссылку.
Небольшие вариации этой логической работы для мягких и phantom ссылок.
Реализация здесь, если вам действительно интересно.
Ответ 3
кеш с использованием слабых ссылок может значительно замедлить ваше приложение, если он восстанавливает запрос по требованию, например. в геттерах:
public Object getSomethingExpensiveToFind() {
if(cache.contains(EXPENSIVE_OBJ_KEY)) {
return cache.get(EXPENSIVE_OBJ_KEY);
}
Object sth = obtainSomethingExpensiveToFind(); // computationally expensive
cache.put(EXPENSIVE_OBJ_KEY, sth);
return sth;
}
представьте этот сценарий:
1) приложение работает с низким объемом памяти
2) GC очищает слабые ссылки, поэтому кеш также очищается
3) приложение продолжает, многие методы, такие как getSomethingExpensiveToFind(), вызывают и восстанавливают кеш
4) приложение снова работает с памятью снова
5) GC очищает ссылки на ношение, очищает кеш
6) приложение продолжает, многие методы, такие как getSomethingExpensiveToFind(), вызывают и снова восстанавливают кеш
7) и т.д.
Я столкнулся с такой проблемой - приложение было очень часто прервано GC, и оно полностью побеждало всю точку кеширования.
Другими словами, при ненадлежащем управлении слабые ссылки могут замедлить ваше приложение.