Есть ли способ определить, насколько легко доступен объект в Java?

Чтобы выполнить некоторое тестирование, я хотел бы проверить, как ведет себя мое приложение, когда удаляются некоторые или все объекты, которые я сохранил в кеше объектов SoftReference.

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

Мое приложение однопоточное, поэтому мне не нужно беспокоиться о мягкой достижимости изменения кэшируемого объекта во время выполнения этого кода. Это также означает, что у меня в настоящее время нет никаких механизмов блокировки - если бы у меня были, я мог бы использовать их, чтобы определить, был ли объект "использован" и, следовательно, доступен ли, но, увы, мне не нужно такой блокировки.

Один из подходов, которые я попробовал, заключается в создании дополнительной SoftReference для каждого объекта, хранящегося в кеше, который зарегистрирован в ReferenceQueue. Я надеялся, что при этом всем мягко достижимым объектам в кеше будет добавлена ​​их дополнительная SoftReference в очередь, поэтому все, что мне нужно было сделать, это перебрать очередь и удалить эти объекты из моего кеша. Тем не менее, кажется, что GC помещает объекты с мягким доступом в их соответствующие очереди на досуге, поэтому не гарантируется, что что-либо будет добавлено в очередь, как только я закончу перебирать объекты в кэше.

Одна вещь, на которую я также обратил внимание, - это опция -XX:SoftRefLRUPolicyMSPerMB JVM с очень маленьким значением. При разумном распределении памяти это вполне вероятно удалит объекты с мягким доступом из кеша для меня в тот момент, когда они будут легко доступны, но я бы очень хотел, чтобы приложение работало нормально до тех пор, пока не получу запрос на удаление объектов с мягким доступом из кеша, Как вариант JVM, я не верю, что смогу изменить это значение во время работы моего приложения.

Итак, есть ли у кого-нибудь идеи относительно того, как я могу определить, является ли объект только мягко достижимым (и, следовательно, может быть очищен)?

Изменить: несколько дополнительных пунктов, которые, возможно, не были ясны:

  • Приложение, вероятно, будет выполнять полезную работу в то время, когда я хочу очистить эти мягко ссылочные объекты. Поэтому я предпочел бы не пытаться заставить GC убирать объекты для меня.
  • Было бы предпочтительнее, если бы я мог выбрать, какие легко достижимые объекты были очищены.
  • Я хотел бы, чтобы приложение работало нормально, т.е. используя настройки производственной памяти. Изменение настроек в коде, которые затем могут быть сброшены до их производственных значений, это хорошо.

3 ответа

Решение

Смешивание некоторых ответов: как сказал Том Хотин, выделяйте память, пока вы не выйдете из памяти, например, с помощью этого кода:

private void doOutOfMemory() {
    try {
        List<byte[]> list = new ArrayList<byte[]>();
        while (true) {
            list.add(new byte[200 * 1024 * 1024]);
        }
    } catch (OutOfMemoryError ex) {
    }
}

Если вы не хотите контролировать, какие объекты очищаются, используйте сильную ссылку на объекты, которые вы хотите сохранить.

Вместо этого вы можете также использовать слабые ссылки и вызывать только System.gc(), чтобы очистить, нет гарантии, что они всегда будут очищены...

IIRC, мягкие ссылки гарантированно (в некотором смысле) очищаются до OutOfMemoryError брошен Таким образом, если вы выделяете много памяти, они должны быть очищены, если на объекты нет сильных ссылок. (Не испытано.)

Замените систему слабых ссылок на текущую систему мягких ссылок во время тестирования.

Система слабых ссылок удалит объекты без других входящих ссылок, как только это произойдет, вместо того, чтобы ждать, пока jvm запустит сборку мусора.

Другие вопросы по тегам