Как SoftReferences собираются JVM на практике?

17

У меня есть два отдельных кэша, работающих в JVM (один контролируется третьей стороной), каждый из которых использует мягкие ссылки. Я бы предпочел, чтобы JVM очистил мой контролируемый кеш до того, который контролируется библиотекой. В javadoc SoftReference указано:

  

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

     

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

Как обычные реализации JVM, особенно HotSpot, обрабатывают SoftReferences на практике? «Уклоняются ли они от устранения недавно созданных или недавно использованных мягких ссылок», как это рекомендовано спецификацией?

    
задан Dave L. 29.03.2012 в 21:47
источник
  • релевантно? Как Hotspot решает очистить SoftReferences –  Miserable Variable 04.04.2012 в 00:37
  • @MiserableVariable Да, весьма уместно, хотя в вашей ссылке отсутствует письмо: jeremymanson.blogspot.com/2009/07/... –  Dave L. 04.04.2012 в 00:56
  • Он не пропустил его раньше, но мне пришлось действовать умным и сделать ссылку из него. Так как я отказываюсь читать документацию и хочу сделать это с помощью проб и ошибок, некоторые реальные материалы иногда удаляются. Кто ухаживает, пока это выглядит красиво? –  Miserable Variable 04.04.2012 в 01:47
  • Если вы хотите переместить свой комментарий, чтобы ответить, я дам вам преимущество и некоторую награду - это был самый полезный источник. –  Dave L. 04.04.2012 в 04:18
  • Раньше я не писал это в ответ, потому что я только цитировал блог. Но я кое-что узнал из вопроса и в блоге, поэтому после вашего предложения я добавил ответ. –  Miserable Variable 04.04.2012 в 18:20

5 ответов

6

Похоже, он может быть настроен, но это не так. Совместимый сборщик меток-зависаний зависает от реализации кучи по умолчанию 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 s для совместимости со всеми четырьмя сборщиками мусора Java 1.4 и с новым сборщиком G1 решение должно лежать только с определением достижимости. К тому моменту, когда возникают жатвы и уплотнения, слишком поздно решить, доступен ли объект. Это предполагает (но не требует), что существует «контекст» коллекции, который определяет доступность, основанную на доступности свободной памяти в куче. Такой контекст должен был бы указать не следующие SoftReference s перед попыткой следовать им.

Так как сборка мусора OutOfMemoryError уклонения специально запланирована в режиме полной коллекции, остановившись в мире, было бы нелегко представить сценарий, когда менеджер кучи устанавливает «не следует за SoftReference », перед созданием коллекции.

--- Хорошо, поэтому я решил, что ответ «должен работать таким образом» просто не был достаточно хорошим.

Из исходного кода src /share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp (основные моменты мои)

Операция на самом деле «делать» сбор мусора:

  170 void VM_GenCollectFullConcurrent::doit() {

Нам лучше быть потоком VM, иначе «программный» поток - сбор мусора!

  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 - это перечисление, которое (догадки здесь) установлено на _allocation_failure в первой попытке избежать OutOfMemoryError и _last_ditch_collection после того, как это не получится (попытаться собрать временный мусор)

Быстрый просмотр в памяти " heap " показывает, что в do_full_collection , которая вызывает do_collection мягких ссылок, явно очищается (в« правильных »условиях) с линией

  480   ClearedAllSoftRefs casr(do_clear_all_soft_refs, collector_policy());

--- Оригинальный пост следует тем, кто хочет узнать о слабых ссылках ---

В алгоритме Mark и Sweep Soft-ссылки not следуют из основного потока (и, таким образом, не отмечены, если другая ветка не может достичь этого через немягкие ссылки.

В алгоритме копирования объекты, на которые ссылаются мягкие ссылки объектов, копируются not (снова, если они не достигнуты с помощью другой несимметричной ссылки).

В основном, следуя сети ссылок из «основного» потока выполнения, мягкие ссылки следуют not . Это позволяет их объектам собирать мусор, как если бы у них не было ссылок, указывающих на них.

Важно отметить, что мягкие ссылки почти изолированы never . Они обычно используются в объектах, где проект должен иметь несколько ссылок на объект, но только одна ссылка должна быть очищена для запуска сбора мусора (для удобства обслуживания контейнера или выполнения времени выполнения, не требующего поиска дорогих ссылок) .     

ответ дан Edwin Buck 29.03.2012 в 21:54
  • Похоже, вы описываете слабые ссылки, а не мягкие ссылки. –  Dave L. 03.04.2012 в 23:46
  • @DaveL. Этого достаточно для меня сегодня вечером. Если вам нужны более конкретные ответы, они, вероятно, довольно близки в приведенной выше ссылке на JVM-код. –  Edwin Buck 04.04.2012 в 01:42
  • Эдвин, спасибо за исследование. Если я правильно понимаю, это указывает на то, что он очистит все мягкие ссылки в сценарии OutOfMemory, что, безусловно, имеет смысл. Тогда возникает вопрос, будет ли он еще очищать некоторые, даже если этот флаг не является смыслом. Часто задаваемые вопросы о HotSpot и блоге Jerermy Manson указывают на то, как это происходит. –  Dave L. 04.04.2012 в 04:11
  • @DaveL. Я думаю, что алгоритм был запланирован, но он не был в этой ветке «горячей точки» (по крайней мере, это было не в нем девять месяцев назад). Коллекторы склонны полагаться на метод must_clear_all_soft_references () кучи, который возвращает true только в _last_ditch_collection, который обычно выполняется только по пути к OutOfMemoryError. Нет причин, по которым это единственный способ сделать это, и многие рамки показывают, что он может быть настроен. Возможно, они просто не смогли найти быстрый чистый способ запуска триггера. Это потребует двойного отслеживания статистики памяти (мягкий и не). –  Edwin Buck 04.04.2012 в 07:42
  • Хотя это может помочь понять, что происходит, обратите внимание, что это всего лишь реализация - она ​​может измениться по желанию. Если вы хотите играть в нее безопасно, придерживайтесь спецификации в Javadoc для SoftReferences. –  Christian Schlichtherle 04.04.2012 в 15:37
3

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

Каким ресурсом является управление кешем? Если его чистый кусок выделяет объект, тогда стратегия не должна иметь значения. Использование ReferenceQueue может помочь вам получить уведомление, когда SoftReference будет очищено.

Если тип ресурса не является только выделенным кучей объектом, тогда вы должны потребовать от своих пользователей вызова метода явной освобождения, то есть Closeable.close (). Чтобы защитить от «забытых» вызовов этого метода выпуска, вы можете рассмотреть возможность применения метода finalize (), но остерегайтесь его побочных эффектов. Для получения дополнительной информации об этом, я рекомендую прочитать «Пункт 7: Избегайте финализаторов» из «Эффективной Java (2-го издания) Джошуа Блоха».

    
ответ дан Christian Schlichtherle 29.03.2012 в 22:19
  • Тем не менее, иногда полезно понять, как реализована ваша JVM и как она ведет себя. –  Dave L. 29.03.2012 в 23:22
  • Да, конечно. Просто не полагайтесь на это. ;-) –  Christian Schlichtherle 29.03.2012 в 23:46
2

Найдена одна часть информации в FAQ HotSpot, которая может быть устаревшей: Ссылка

  

Что определяет, когда объекты с мягкой ссылкой сброшены?

     

Начиная с 1.3.1, объекты с мягким достижением будут оставаться живыми для   некоторое количество времени после последнего обращения к ним.   значение по умолчанию - одна секунда от продолжительности жизни за один мегабайт в куче.   Это значение можно настроить с помощью флага -XX: SoftRefLRUPolicyMSPerMB,   который принимает целочисленные значения, представляющие миллисекунды. Например,   для изменения значения с одной секунды до 2,5 секунд используйте этот флаг:

     

-XX: SoftRefLRUPolicyMSPerMB = 2500      

Виртуальная машина Java HotSpot использует максимально возможный размер кучи (как установлено   с опцией -Xmx), чтобы вычислить оставшееся свободное пространство.

     

Клиент VM Hotspot Client использует текущий размер кучи для вычисления   свободное пространство.

     

Это означает, что общая тенденция заключается в том, что VM   куча, а не мягкие ссылки, и поэтому -Xmx имеет   значительное влияние на то, когда мягкие ссылки собирают мусор.

     

С другой стороны, клиентская VM будет иметь большую тенденцию к потоку   мягкие ссылки, а не рост кучи.

     

Поведение, описанное выше, верно для 1.3.1 через Java SE 6   версии виртуальных машин Java HotSpot. Это поведение не является частью виртуальной машины   спецификация, однако, и может быть изменена в будущих выпусках.   Аналогично, флаг -XX: SoftRefLRUPolicyMSPerMB не гарантирован   присутствовать в любом выпуске.

     

До версии 1.3.1 виртуальные машины Java HotSpot очистили мягкие ссылки   когда он их нашел.

Более подробную информацию можно найти по адресу: Ссылка (любезно предоставлено Комментарий MiserableVariable)

    
ответ дан Dave L. 03.04.2012 в 23:59
2

Не то, чтобы это было авторитетно, но с использованием SoftReference в гневе. Я никогда не видел, чтобы виртуальная машина стирала их вместо увеличения размера виртуальной машины. На самом деле я почему-то предполагал, что это так, и дизайн очень сильно зависит от этого. У меня были одинаковые -ms и -mx , но это не имело значения.

Но я не могу найти какой-либо спецификации, которая на самом деле говорит, что это необходимо. Этот блог, похоже, содержит подробные сведения о том, как SoftReferences очищено. Из быстрого чтения это действительно похоже на они могут быть очищены, даже если доступна другая память.     

ответ дан Miserable Variable 04.04.2012 в 18:18
  • Почему downvote :( –  Miserable Variable 04.01.2014 в 18:11
0

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

Кажется свернутым. Вероятно, я бы склонялся к тому, чтобы просто признать, что оба кэша - это именно то, кэш. Недостатки кэша могут быть болезненными для производительности, но по крайней мере у вашего программного обеспечения не будет сложной стратегии управления кешем.

    
ответ дан Tim Bender 04.04.2012 в 00:19