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

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

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

есть ли способ получить Java больше нетерпеливо прояснить мягкие ссылки?


нашел здесь:

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

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

10 ответов


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

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

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

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


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

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


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

-XX:SoftRefLRUPolicyMSPerMB=<value>

где 'value' - количество миллисекунд, на которые останется мягкая ссылка для каждого свободного Мб памяти. Значение по умолчанию-1s / Mb, поэтому, если объект доступен только мягко, он будет длиться 1s, если только 1Mb пространства кучи свободен.


вы можете заставить все SoftReferences очищаться в ваших тестах с помощью этого кусок кода.


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

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

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

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


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

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


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


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

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


Если вы используете eclipse, есть этот инструмент с именем Анализатор Памяти это упрощает отладку дампа кучи.


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


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