Коллекции Java и сборщик мусора

Небольшой вопрос относительно производительности в веб-приложении Java.

Предположим, что у меня есть List<Rubrique> listRubriques с десятью объектами Rubrique.

A Rubrique содержит один список продуктов (List<product> listProducts) и один список клиентов (List<Client> listClients).

Что именно происходит в памяти, если я это делаю:

listRubriques.clear(); listRubriques = null;

Моя точка зрения будет заключаться в том, что, поскольку listRubriques пуст, все мои объекты, ранее упомянутые этим списком (включая listProducts и listClients), будут собираться с мусором в ближайшее время. Но так как сборка на Java немного сложна, и поскольку у меня проблемы с производительностью с моим приложением, я задаю вопрос:)

edit: допустим, что мой объект Client содержит List<Client>. Поэтому у меня есть круговая ссылка между моими объектами. Что произойдет, если мой listRubrique установлен на null? На этот раз моя точка зрения будет заключаться в том, что объекты моего Клиента станут "недоступными" и могут создать утечку памяти?

Ответ 1

Фактическая реализация Sun для Java копирует время от времени все объекты, на которые ссылаются/живут. Пространство, из которого было скопировано, можно затем снова использовать для выделения памяти.

Это говорит о том, что ваши примеры на самом деле влияют на производительность. listRubriques.clear() является ненужным (за исключением того, что у вас где-то еще есть ссылка на него), потому что все, на что ссылается listRubrique, является мусором в списке моментаRubriques больше не ссылается. listRubriques = null также может быть ненужным, если после этого переменная listRubriques выходит из области видимости (возможно, из-за того, что локальная переменная и метод заканчиваются здесь).

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

Эта статья является хорошей ссылкой для получения дополнительной информации о сборщике Java Garbage.

РЕДАКТИРОВАТЬ. Чтобы отреагировать на редактирование в вопросе: сборщик мусора (реализация, используемая Sun по крайней мере), начинается с некоторых корневых ссылок и копирует все объекты, которые он может достичь из этих ссылок и на которые ссылаются скопированные объекты. Таким образом, ваши объекты с круговыми ссылками являются мусором, так как к ним не обращается "внешняя" ссылка, и память будет возвращена в сборку мусора.

Ответ 2

Если у вас есть:

listRubriques = null;

и нет других объектов, содержащих ссылки на listRubriques или его содержащие объекты, которые могут быть использованы для сбора мусора. Но нет никакой гарантии, что когда JVM фактически запустит сборку мусора и освободит память. Вы можете позвонить:

System.gc();

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

Кроме того,

listRubriques.clear();

перед установкой listRubriques в null не требуется.

EDIT. Чтобы ответить на ваш вопрос о циклических ссылках, JVM достаточно умны, чтобы понять, что весь графический объект отключен от любого активно работающего кода, и JVM правильно определит, что все они имеют право для сбора мусора. Это всегда было правдой даже в плохие старые часы отсчета. Современные JVM только быстрее и эффективнее. Но они не мусор, собирающий больше объектов, чем более старые JVM.

Ответ 3

"Довольно скоро" - довольно неопределенная спецификация, но сборщик мусора, вероятно, не так быстр, как вы, кажется, ожидаете. Когда собираемые объекты будут собираться, многое зависит от конфигурации GC и загрузки вашего сервера, но это может занять некоторое время, и если ваша виртуальная машина будет иметь достаточно кучу и другие вещи, объекты не будут собраны "довольно скоро",

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