Похоже, что это может быть настроено, но это не так. Параллельный сборщик разметки зависает при реализации кучи по умолчанию must_clear_all_soft_refs()
, которая, по-видимому, составляет всего true
при выполнении _last_ditch_collection
.
bool GenCollectedHeap::must_clear_all_soft_refs() {
return _gc_cause == GCCause::_last_ditch_collection;
}
В то время как обычная обработка неудачного выделения имеет три последовательных вызова метода do_collect
кучи, в CollectorPolicy.cpp
HeapWord* GenCollectorPolicy::satisfy_failed_allocation(size_t size,
bool is_tlab) {
Который пытается собрать, пытается перераспределить, пытается расширить кучу, если это не удается, и затем, как последнее усилие, пытается собрать очищающие мягкие ссылки.
Комментарий к последней коллекции довольно показателен (и единственный, который вызывает очистку мягких ссылок)
// If we reach this point, we're really out of memory. Try every trick
// we can to reclaim memory. Force collection of soft references. Force
// a complete compaction of the heap. Any additional methods for finding
// free memory should be here, especially if they are expensive. If this
// attempt fails, an OOM exception will be thrown.
{
IntFlagSetting flag_change(MarkSweepAlwaysCompactCount, 1); // Make sure the heap is fully compacted
gch->do_collection(true /* full */,
true /* clear_all_soft_refs */,
size /* size */,
is_tlab /* is_tlab */,
number_of_generations() - 1 /* max_level */);
}
--- Отредактировано в ответ на очевидное, я описываю слабые ссылки, а не мягкие ---
На практике я мог бы представить, что SoftReferences следуют только "не", когда JVM вызывается для сборки мусора в ответ на попытку избежать OutOfMemoryError
.
Для обеспечения совместимости SoftReference
со всеми четырьмя сборщиками мусора Java 1.4 и с новым сборщиком G1 решение должно приниматься только при определении достижимости. К тому времени, когда произойдут пожатия и сжатие, уже слишком поздно решать, достижим ли объект. Это предполагает (но не требует), что существует «контекст» коллекции, который определяет достижимость на основе доступности свободной памяти в куче. Такой контекст должен указывать на несоблюдение SoftReference
s, прежде чем пытаться следовать им.
Поскольку OutOfMemoryError
сборка мусора во избежание специально спланирована в режиме полного сбора, остановка мира, нетрудно представить сценарий, когда менеджер кучи устанавливает "не следовать SoftReference
" флаг перед сбором.
--- Хорошо, поэтому я решил, что ответ "должен работать таким образом" просто недостаточно хорош ---
Из исходного кода src / share / vm / gc_implementation / concurrentMarkSweep / vmCMSOperations.cpp (основные моменты мои)
Операция, которая фактически "делает" сборку мусора:
170 void VM_GenCollectFullConcurrent::doit() {
Лучше быть потоком виртуальной машины, иначе поток "программы" будет собирать мусор!
171 assert(Thread::current()->is_VM_thread(), "Should be VM thread");
Мы являемся одновременным сборщиком, поэтому лучше планировать его одновременно!
172 assert(GCLockerInvokesConcurrent || ExplicitGCInvokesConcurrent, "Unexpected");
173
Возьмите кучу (в которой есть объект GCCause).
174 GenCollectedHeap* gch = GenCollectedHeap::heap();
Проверьте, нужна ли нам на переднем плане "молодая" коллекция
175 if (_gc_count_before == gch->total_collections()) {
176 // The "full" of do_full_collection call below "forces"
177 // a collection; the second arg, 0, below ensures that
178 // only the young gen is collected. XXX In the future,
179 // we'll probably need to have something in this interface
180 // to say do this only if we are sure we will not bail
181 // out to a full collection in this attempt, but that's
182 // for the future.
Потоки программы не вмешиваются в кучу?
183 assert(SafepointSynchronize::is_at_safepoint(),
184 "We can only be executing this arm of if at a safepoint");
Извлечь причину сборки мусора (причину этой сборки) из кучи.
185 GCCauseSetter gccs(gch, _gc_cause);
Сделай полную коллекцию молодого космоса
Обратите внимание, что он передает значение флага must_clear_all_soft_refs кучи
Который в сценарии OutOfMemory должен быть установлен в true, и в любом случае
указывает "do_full_collection" не следовать мягким ссылкам
186 gch->do_full_collection(gch->must_clear_all_soft_refs(),
187 0 /* collect only youngest gen */);
_gc_cause - это enum, для которого (догадка здесь) установлено значение _allocation_failure
в первой попытке избежать OutOfMemoryError
и _last_ditch_collection
после того, как это не удастся (попытаться собрать временный мусор)
Быстрый просмотр в модуле «кучи» памяти показывает, что в do_full_collection
, который вызывает do_collection
мягкие ссылки, очищаются явно (при «правильных» условиях) с помощью строки
480 ClearedAllSoftRefs casr(do_clear_all_soft_refs, collector_policy());
--- Оригинальный пост следует для тех, кто хочет узнать о слабых ссылках ---
В алгоритме Mark and Sweep мягкие ссылки не следуют из основного потока (и, следовательно, не помечаются, если другая ветвь не может достичь его через не-мягкие ссылки.
В алгоритме копирования мягкие ссылки на объекты указывают на то, что не скопированы (опять же, если они не достигнуты другой несвязной ссылкой).
В основном, когда вы следите за паутиной ссылок из "основного" потока исполнения, следуют программные ссылки , а не . Это позволяет их объектам собирать мусор так, как если бы у них не было ссылок на них.
Важно отметить, что мягкие ссылки почти никогда не используются изолированно. Они обычно используются в объектах, где дизайн должен иметь несколько ссылок на объект, но только одна ссылка должна быть очищена для запуска сборки мусора (для простоты обслуживания контейнера или производительности во время выполнения без необходимости искать дорогие ссылки) .