2009-12-31 4 views
24

Я довольно новичок в изучении C# (из Java & C++ background), и у меня есть вопрос об утилизации мусора вручную: возможно ли даже вручную уничтожить объект на C#? Я знаю об интерфейсе IDisposable, но предположим, что я имею дело с классом, который я не писал, и он не реализует его? У него не было бы метода .Dispose(), так что и using { } отсутствовал, а .Finalize всегда либо protected, либо private, так что это тоже не вариант.Вручную уничтожить объекты C#

(я просто пытаюсь узнать, что находится в C# в этом случае возможно. Я полагаю, что если все остальное не могу наследовать гипотетический ImNotDisposable класс так, чтобы он делает реализации IDisposable.)

+3

Возможно, вам следует пояснить вопрос: хотите ли вы полностью освободить объект или просто заставить его метод деструктора выполнить и очистить ресурсы объекта (только)? –

+0

Я предполагал, что один подразумевал другой, но то, что я имел в виду, было каким-то способом «вызвать» метод ClassName(), который имеет объект. –

+0

Итак, GC имеет метод Collect(), который практически не имеет ничего общего и никоим образом не нацелен на какой-либо конкретный объект. Попался. :) –

ответ

24

Вы не уничтожаете вручную объекты .Net. Вот что такое управляемая среда.

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

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

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

+4

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

+1

@MongusPong: 'Dispose' очень важен, но он не« разрушает »объекты - вместо этого он уведомляет их о том, что их услуги больше не требуются, так что другие сущности (действующие от их имени (если они существуют) могут быть уведомили в свою очередь, что * их * услуги больше не требуются. – supercat

+0

Я полностью не согласен с общим утверждением: «Вы должны использовать его только для типов, которые обертывают неуправляемые ресурсы». Я знаю, что это обычная мудрость, но если вы столкнетесь с проблемами утечки памяти , очень полезно делать предметы одноразовыми. Причина в том, что хорошие приложения для отслеживания памяти смогут показать вам объекты, которые были удалены, но еще не были разрушены. Он четко показывает, что вы отметили для уничтожения, но не имеет Кроме того, это дает вам хорошую возможность и стандартное место для удаления обработчиков событий и т. д., чтобы сетка была правильно сломана. –

6

Если объект недоступен, вы можете позвонить GC.Collect() и объект будет уничтожен. Концепция IDisposable не имеет ничего общего с CLR и в основном используется для кода пользователя для выполнения для выполнения дополнительных логики удаления. Вызов Dispose() на объект не освободит объект от памяти, хотя он может очень хорошо распоряжаться любыми ресурсами, которые этот объект ссылается.

Я хотел бы добавить, что в то время как то, что я сказал, это способ для достижения этой цели, в 99,9999% приложений, которые вы никогда не должны вызывать GC.Collect(), потому что он будет часто деградировать производительность вашего приложения, а не улучшить его.

+3

вызов 'GC.Collect()' не то, что вы должны делать, если только это не для * очень * веской причины. –

+0

, чтобы добавить к этому, он будет собирать только объект, если больше нет ссылок на этот объект. – McAden

+1

Речь идет не о ссылках на объект - речь идет о достижимости (что я упоминаю). – Eilon

5

Нет, вы не можете уничтожить определенный объект.

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

3

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

Форсировать сбор мусора можно с помощью GC.Collect, но не делайте этого. За 10 лет работы в качестве разработчика .NET я никогда не нуждался в этом.

1

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

Счастливое кодирование,

Скотт

+1

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

1

Вы не вручную уничтожить объект «как C++ удалить», все, что вы можете сделать, это просто закрыть все эксклюзивные ресурсы объект приобрел и нуль все ссылки на этот объект, поэтому GC может его собрать, также не вызывать GC.Collect() самостоятельно, процесс GC дорогой, поскольку он должен приостановить все остальные потоки, чтобы безопасно собирать объекты из памяти, так что просто доверьтесь GC, и он начнется, когда потребуется.

+3

Ну, я бы никогда не назначил какие-либо ссылочные переменные нулевому значению, например myObj = null; Я бы просто позволил им выйти из сферы действия. –

+1

Согласен, я бы скорее попытался сделать это, если возможно – bashmohandes

6

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

Furtnermore, так как финализация происходит в собственной нити, вы должны позвонить WaitForPendingFinalizers после запуска сбора мусора.

GC.Collect(GC.MaxGeneration); 
GC.WaitForPendingFinalizers(); 

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

Вообще говоря, класс, реализующий финализатор (деструктор) и не реализующий IDisposable, неодобрительно. И все, что реализует IDisposable, должно вызывать его логику финализатора и пресекать себя от финализации при сборе мусора.

Джефф Рихтер недавно опубликовал хороший небольшой трюк для receiving a notification when garbage collection occurs.

Еще одна интересная статья на Garbage Collector Basics and Performance Hints от Rico Mariani (MSFT)

0

Скажем у вас есть матрица класса и вы создали две матрицы объектов aMatrix и bMatrix. В C# вы можете вручную уничтожить (завершить) такой объект:

aMatrix = NULL;

GC.Collect();

Сборщик мусора заметит, что ваша aMatrix NULL и уничтожит (завершает) его. Независимо от того, является ли это хорошей идеей, это совсем другая история.