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

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

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

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

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

listRubriques.clear(); listRubriques = null;

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

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


person Anth0    schedule 18.01.2010    source источник


Ответы (3)


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

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

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

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

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

person Mnementh    schedule 18.01.2010
comment
Осторожно: ваше первое предложение описывает текущую реализацию Sun JVM. Это утверждение не относится к Java в целом. Однако остальная часть ответа, кажется, применима в целом ». - person Joachim Sauer; 08.03.2010
comment
Спасибо за подсказку, я изменил первое предложение. - person Mnementh; 08.03.2010

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

listRubriques = null;

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

System.gc();

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

Также имея

listRubriques.clear();

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

РЕДАКТИРОВАТЬ: чтобы ответить на ваш вопрос о циклических ссылках, JVM достаточно умен, чтобы выяснить, что весь граф объектов отключен от любого активно работающего кода, и JVM правильно определит, что все они имеют право на сборку мусора. . Это всегда было правдой, даже в старые плохие времена подсчета ссылок. Современные JVM просто быстрее и эффективнее. Но они не собирают мусор больше, чем старые JVM.

person Asaph    schedule 18.01.2010
comment
Что касается очистки до нуля, я сделал это просто для того, чтобы быть уверенным, что у моего объекта больше не будет ссылок. Но я в порядке, это бесполезная двойная проверка. Я читал System.gc (); был полезен в старых версиях Java, но в настоящее время полностью игнорируется, не так ли? - person Anth0; 18.01.2010
comment
@ Anth0: Я не слышал об этом, и в документации J2SE для Java 6 ничего подобного не упоминается (java.sun.com/javase/6/docs/api/java/lang/System.html#gc ()). Для максимальной переносимости лучше не делать никаких предположений о реализации JVM, на которой будет работать ваше приложение. Прочтите эту статью от Sun, чтобы узнать правду о сборке мусора: java.sun.com/docs/books/performance/1st_edition/html/ - person Asaph; 18.01.2010
comment
Вызов System.gc () обычно присуждается и более новыми виртуальными машинами, хотя и не гарантируется. Если вы запрашиваете запуск GC, хотя в этом нет необходимости, вы, тем не менее, потенциально создаете проблему с производительностью, а не решаете ее. - person jarnbjo; 18.01.2010
comment
Большое спасибо за вашу ссылку. Я многому научился! А я отредактирую свой вопрос :) - person Anth0; 18.01.2010
comment
@ Anth0: Я обновил свой ответ. Не беспокойтесь о круговых ссылках. JVM всегда была достаточно умен, чтобы справиться с этим крайним случаем. Для более подробного обсуждения прочитайте всю правду о ссылке на сборку мусора, которую я разместил в моем комментарии выше, в Разделе A.3.4. - person Asaph; 18.01.2010

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

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

person jarnbjo    schedule 18.01.2010