Когда я должен размещать свои объекты в .NET? - PullRequest
18 голосов
/ 29 октября 2008

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

Ответы [ 8 ]

26 голосов
/ 29 октября 2008

Утилизируйте объект, как только вы закончите с ним. Одноразовые объекты представляют собой объекты, содержащие ценный ресурс, о котором CLR изначально не осведомлен. Следовательно, GC также не осведомлен о ресурсах и не может принимать разумные решения относительно того, когда ему следует собирать одноразовый предмет и, следовательно, освобождать лежащий в основе ресурс.

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

Быстрый пример того, как это может произойти. Давайте рассмотрим базовый ресурс как дескриптор Win32. Они очень конечны и довольно малы. Вы запускаете операцию, которая создает много объектов Foo. Объекты Foo реализуют IDisposable и отвечают за создание и удаление дескриптора Win32. Они не освобождаются вручную и, как ни странно, превращаются в кучу Gen2. Эта куча освобождается довольно редко. Со временем достаточное количество экземпляров Foo попадает в кучу Gen2, чтобы занять все доступные дескрипторы. Следовательно, новые объекты Foo невозможно создать независимо от того, сколько памяти используется.

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

15 голосов
/ 29 октября 2008

Если объект реализует IDisposable, вы должны избавиться от него, как только закончите с ним. Самый простой способ - окружить его , используя блок:

using (SqlCommand cmd = new SqlCommand(conn)) {
    cmd.ExecuteNonQuery();
}
6 голосов
/ 29 октября 2008

Причина, по которой вы всегда должны вызывать Dispose() для любого типа, реализующего IDisposable, заключается в том, что он обычно используется для обозначения того, что тип получает неуправляемые ресурсы. Особенно важно, чтобы они были освобождены и как можно раньше. Как уже упоминалось, using является предпочтительным способом сделать это.

3 голосов
/ 29 октября 2008

Есть несколько способов взглянуть на это. Один из способов пытается выяснить, действительно ли необходимо избавиться от объекта, как только он больше не нужен, например, с помощью Reflector, чтобы определить, удерживает ли он действительно неуправляемые ресурсы, или они были случайно удалены в любом случае. Другая перспектива состоит в том, чтобы предположить, что если объект реализует IDisposable, не ваша задача определить, действительно ли нужно вызывать Dispose () - вы всегда вызываете его. Я думаю, что это правильный путь. Если заглянуть в частную реализацию объектов и принять решение о том, как их использовать, вы рискуете быть связанным с реализацией, которая может измениться. Примером является LINQ to SQL DataContext. Он реализует IDispose, но в основном очищается после себя без необходимости явного вызова Dispose (). Я предпочитаю писать код, который в любом случае явно удаляется, но другие считают, что в этом нет необходимости.

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

И, как уже было сказано, использование (..) {...} - ваш друг для разработчиков IDisposable.

1 голос
/ 29 октября 2008

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

0 голосов
/ 29 октября 2008

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

Вы можете избежать вызова Dispose, написав свой код освобождения в методе Finalize, но тогда вы зависите от сборщика мусора, потому что вы никогда не знаете, когда сборщик мусора завершит ваш объект. Чтобы быть в безопасности, если вы разрабатываете такой класс, который содержит неуправляемый ресурс, вы можете написать один и тот же код освобождения объекта в обоих методах Dispose и Finalize, но если вы делаете это, всегда используйте SuppressFinalize () в вашем методе dispose потому что это предотвратит вызов метода Finalize (), если ваш объект уже находится в очереди финализации.

0 голосов
/ 29 октября 2008

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

0 голосов
/ 29 октября 2008

Опираясь на ГК "работает" в большинстве случаев. Классическое исключение - когда у вас интенсивное взаимодействие с ресурсами - в этом случае лучше всего распоряжаться явным образом.

очевидно, например.

using (var conn = new SqlConnection(connString)) {}

Блоки «Использование» - безусловно, самый чистый и надежный метод обеспечения правильной утилизации объектов. Блоки «Использование» можно использовать с любыми объектами, которые реализуют IDisposable.

...