2012-01-11 3 views
2

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

Когда я смотрю на примеры внутреннего класса в режиме отладки, после того, как создатель должен был быть собран, я нахожу ссылку под названием this$0, которая указывает на объект, который должен быть мертв.

Есть ли способ предотвратить ссылку Outer.this от создания java в каждом экземпляре Inner? Это поле не используется в программе, и все, что он делает, это предотвращение сбора мусора, что приводит к тому, что куча заканчивается из памяти. Перемещение Inner из Outer не является вариантом, поскольку оно содержит поля данных public, которые должны быть видны только Outer.

+1

Как вы подтвердили, что это не GCed? – kosa

+0

Да, этот $ 0, который я вижу в режиме Debug, все еще находится в памяти и может быть просмотрен. – user1123936

+0

Знаете ли вы, что экземпляры не являются GC'ed, когда вы запускаете без отладчика? Возможно, их поддерживают, чтобы отладчик мог их отображать. Я нашел (как минимум, в Eclipse), что сборщик мусора часто работает в режиме отладки в режиме запуска. –

ответ

4

Ваш внутренний класс поддерживает this$0, чтобы он мог получить частные поля и методы внешнего класса. Если вашему внутреннему классу не нужно ничего использовать во внешнем классе, вы можете пометить внутренний класс static, чтобы он не поддерживал ссылку на экземпляр содержащего класса.

+0

Внутренний класс не является статичным, поскольку я создаю много его экземпляров. – user1123936

+2

@ user1123936 - Вы не понимаете, что такое статический внутренний класс. Он может иметь несколько экземпляров. –

+0

Я скептически отношусь к этому. Несмотря на это, мне нужно, чтобы мой внутренний класс был нестационарным, потому что каждый экземпляр его должен вызывать нестатические методы, которые используют нестатические данные экземпляра. – user1123936

0

О том, что вы можете сделать, это сделать внутренние классы статическими или вообще не использовать внутренние классы.

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

4

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

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


Followup

Что бы вы порекомендовали тогда? Я понятия не имею, как использовать пакеты, но мне нужно создать экземпляры Inner, которые имеют общедоступные поля данных, доступные только Outer, и могут выжить после уничтожения Outer. Мне повезло?

Перед тем, как ответить на ваш вопрос:

  • «Я понятия не имею, как использовать пакеты ...» - вы должны узнать о них потом. Пакеты и доступ к частным пакетам являются важной частью языка Java.

Теперь на ваш вопрос ...

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

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

  • Если вы объявите Inner классом как private static class Inner, то методы класса Inner НЕ МОЖЕТ вызвать методы экземпляра или получить доступ к полям экземпляра Outer ... если у них нет ссылки и Outer экземпляр (например, передан как параметр). Если Inner - static, срок службы экземпляров Inner и Outer являются независимыми.

  • Если вы объявляете Inner класс как private class Inner, то методы в Inner классе могут вызывать методы экземпляра или экземпляр доступа поле Outer. Но обратная сторона заключается в том, что время жизни экземпляра Outer и его экземпляры Inner теперь зависят. Конкретно, экземпляр Outer будет существовать до тех пор, пока по крайней мере один из его экземпляров Inner продолжает существовать. (Обратное не верно ... если экземпляр Outer не держит ссылки на Inner экземпляров в (скажем) в области сбора типизированных.)

Просто пересчитывать то, что я сказал ранее. Если экземпляру Inner необходимо получить доступ к полям экземпляра или вызвать методы экземпляра на экземпляре Outer, тогда ему требуется явная ссылка или ссылка на этот экземпляр Outer. Это означает, что экземпляр Outer доступен и не является кандидатом для удаления сборщиком мусора.

Другой момент - это пример Inner, который не исчезнет, ​​если он еще доступен; т. е. если какая-то часть вашего запущенного приложения имеет ссылку на экземпляр, который он мог бы использовать. В Java объекты НЕ получают сбор мусора, если есть любая возможность, что они могут использоваться запущенным приложением. Экземпляры внутренних/вложенных классов не являются особыми в этом отношении.


На самом деле, может быть (действительно противный!) Способ сделать это разорвать связь между Inner и Outer экземпляров. Если вы можете найти все экземпляры Inner, вы можете использовать отражение, чтобы назначить null скрытой переменной this$0 в каждой из них. Однако, если вы это сделаете, любой код в классе Inner, который ссылается на состояние экземпляра Outer, сломается. Если вы собираетесь прибегнуть к такой гадости, вам лучше объявить Inner классом static.

+0

Что вы рекомендовали бы тогда? Я понятия не имею, как использовать пакеты, но мне нужно создавать экземпляры Inner, которые имеют общедоступные поля данных, доступные только для Outer, и могут выжить после уничтожения Outer. Мне повезло? – user1123936

+0

Что вы подразумеваете под «общедоступными полями данных, доступными только для Outer»? Являются ли они «общедоступными» или они «доступны только для Внешних» ?. Если вы можете это прояснить, это может привести к решению проблемы. –

+0

Поля данных Inner объявляются общедоступными, но они доступны только для Outer, потому что класс Inner объявлен как закрытый для Outer. – user1123936

Смежные вопросы