Подтвердить что ты не робот

Как заставить мягкие ссылки очищаться на Java?

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

Проблема заключается в следующем: я не могу надежно получить мягкие ссылки для очистки. Просто использование кучи памяти не делает трюк: я получаю OutOfMemory, прежде чем любые мягкие ссылки будут очищены.

Есть ли способ заставить Java более охотно очищать мягкие ссылки?


Найдено здесь:

"Гарантируется, что все SoftReferences будет очищено до OutOfMemoryError бросается, поэтому они теоретически не может вызвать OOME."

Значит ли это, что вышеупомянутый сценарий ДОЛЖЕН означать, что у меня есть утечка памяти где-то с некоторым классом, содержащим жесткую ссылку на мой кешированный объект?

4b9b3361

Ответ 1

Проблема в том, что я не могу показаться надежно получить мягкие ссылки очищено.

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

Object temp = new Object();
temp = null;
System.gc();

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


Тем не менее, в соответствии с цитируемыми вами Javadocs, SoftReferences обязательно следует очистить до того, как будет выброшен OutOfMemoryError (на самом деле, что все их значение и единственный способ, которым они отличаются от ссылок на объекты по умолчанию). Таким образом, было бы похоже, что есть какая-то утечка памяти, в которой вы держитесь за более сложные ссылки на объекты, о которых идет речь.

Если вы используете параметр -XX:+HeapDumpOnOutOfMemoryError для JVM, а затем загрузите кучу кучи в нечто вроде jhat, вы должны быть способный видеть все ссылки на ваши объекты и, таким образом, видеть, есть ли какие-либо ссылки рядом с вашими мягкими. В качестве альтернативы вы можете добиться того же самого с профилировщиком во время выполнения теста.

Ответ 2

Существует также следующий параметр JVM для настройки того, как обрабатываются мягкие ссылки:

-XX:SoftRefLRUPolicyMSPerMB=<value>

Где "значение" - это количество миллисекунд, то для каждого бесплатного Мбайта памяти останется мягкая ссылка. Значение по умолчанию - 1 с/Мб, поэтому, если объект доступен только для достижения цели, он будет длиться 1 с, если только 1 Мб свободного пространства.

Ответ 3

Вы можете заставить все SoftReferences быть очищены в ваших тестах с помощью части кода.

Ответ 4

Если вы действительно этого хотели, вы можете вызвать clear() на SoftReference, чтобы очистить его.

Тем не менее, если JVM выбрасывает OutOfMemoryError, и ваше SoftReference еще не очищено, это означает, что вы должны иметь твердую ссылку на объект где-то еще. В противном случае будет аннулирован контракт SoftReference. В противном случае вам никогда не гарантируется, что SoftReference будет очищен: пока имеется доступная память, JVM не нужно очищать SoftReferences. С другой стороны, разрешается очищать их в следующий раз, когда выполняется цикл GC, даже если это не нужно.

Кроме того, вы можете рассмотреть возможность поиска в WeakReferences, так как виртуальная машина имеет тенденцию быть более агрессивной, чтобы очистить их. Технически, VM никогда не требуется очищать WeakReference, но предполагается, что они очистят их в следующий раз, когда цикл GC, если объект в противном случае считается мертвым. Если вы пытаетесь проверить, что происходит, когда ваш кеш очищается, использование WeakReferences поможет вам быстрее уйти.

Кроме того, помните, что оба они зависят от JVM, выполняющего цикл GC. К сожалению, нет никакого способа гарантировать, что один из них когда-либо случится. Даже если вы вызываете System.gc(), сборщик мусора может решить, что он делает просто peachy и не хочет ничего делать.

Ответ 5

В типичной реализации JVM (SUN) вам нужно запустить Full GC более одного раза, чтобы очистить Softreferences. Причина этого в том, что Softreferences требует, чтобы GC выполнял больше работы, потому что, например, механизм, который позволяет вам получать уведомления, когда объекты возвращаются.

ИМХО, использующее множество советов на сервере приложений, является злым, потому что разработчик не имеет большого контроля над выпуском.

Ответ 6

Сбор мусора и другие ссылки, такие как мягкие ссылки, не являются детерминированными, что на самом деле невозможно надежно сделать что-то, чтобы мягкие ссылки определенно очищались в этот момент, поэтому ваш тест может судить о том, как реагирует ваш компьютер. Я бы предложил вам более точно моделировать обратную очистку, насмехаясь и т.д. - ваши тесты будут воспроизводимыми и более ценными, а не просто Hopi g для GC, чтобы очищать ссылки. Использование последнего подхода - это очень плохо, и вам придется вводить дополнительные проблемы, а не улучшать качество кеша и его взаимодействующих компонентов.

Ответ 7

Из документации и моего опыта я бы сказал "да": у вас должна быть ссылка где-то еще.

Я бы предложил использовать отладчик, который может показать вам все ссылки на объект (например, Eclipse 3.4 при отладке Java 6) и просто проверить, когда брошен OOM.

Ответ 8

Если вы используете eclipse, есть этот инструмент с именем Memory Analyzer, который облегчает отладку дампа кучи.

Ответ 9

У кэшированного объекта есть финализатор? Финализатор создаст новые сильные ссылки на объект, поэтому даже если SoftReference будет очищен, память не будет восстановлена ​​до следующего цикла GC

Ответ 10

Если у вас есть кэш, который является Map of SoftReferences, и вы хотите, чтобы они были очищены, вы можете просто очистить() карту, и все они будут очищены (включая их ссылки).