Действительно ли использованием является Экземпляр класса, поскольку Карта включает лучшую практику?

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

Map<Class<?>,String> classToInstance = new HashMap();

classToInstance.put(String.class,"Test obj");
37
задан Harry 9 November 2016 в 20:11
поделиться

4 ответа

Да, надо быть осторожным! Например, если ваш код выполняется в веб-контейнере, и у вас есть привычка выполнять горячее развертывание веб-приложений, сохраненная ссылка на один объект класса может вызвать значительную утечку памяти permgen.

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

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

  1. Старая и новая версии класса не будут равны.
  2. Поиск нового класса изначально даст «промах».
  3. После того, как вы добавили новый класс на карту, теперь у вас будет две разные записи карты для разных версий класса.
  4. Это применимо, даже если между двумя версиями класса нет разницы в коде . Они будут разными просто потому, что были загружены разными загрузчиками классов.

Из Java 8 - Permgen был удален. Как вы думаете, можно ли использовать экземпляр класса в качестве ключа HashMap в любых ситуациях?

Имейте в виду, что у вас все равно будет утечка памяти. Любой динамически загружаемый класс, используемый в вашем HashMap (ключ или значение) и (по крайней мере) другие динамически загружаемые классы, будет оставаться доступным. Это означает, что сборщик мусора не сможет выгрузить / удалить их.

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

23
ответ дан 27 November 2019 в 05:02
поделиться

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

5
ответ дан 27 November 2019 в 05:02
поделиться

Это зависит от того, где определена ссылка classToInstance=new HashMap();.

Класс указывает обратно на свой загрузчик классов, и, как следствие, загрузчик классов не может быть собран в мусор, пока существует ссылка на класс. Но если ссылки образуют круг (или недостижимый кластер), это все равно работает - GC знает, как работать с круговыми ссылками.

parent class loader --> class loader <--> class  // no GC is possible
parent class loader     class loader <--> class  // circular references are GC'ed

Таким образом, ссылка на класс может предотвратить GC загрузчика класса, только если ссылки исходят от объекта/класса в родительском загрузчике класса.

parent class loader     class loader <--> class  // no GC is possible
                    \-------------------/

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

Но это не должно быть так, если карта является частью вашего приложения.

0
ответ дан 27 November 2019 в 05:02
поделиться

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

mapkey --> class --> classloader --> all other classes defined by this classloader.

Кроме того,

class --> any static members, including static Maps e.g. caches.

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

Есть несколько подходов к решению этой проблемы. Если вас не интересуют разные «версии» одного и того же класса из разных загрузчиков классов, просто введите ключ на основе Class.getName () , который является java.lang.String .

Другой вариант - использовать java.util.WeakHashMap . Эта форма Map поддерживает только слабые ссылки на ключи. Слабые ссылки не задерживают сборщик мусора, поэтому они не вызывают накопления памяти. Однако значения , а не слабо указаны. Поэтому, если значения являются, например, экземплярами классов, используемых в качестве ключей, WeakHashMap не работает.

2
ответ дан 27 November 2019 в 05:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: