Очистка ресурсов (сборка мусора, использование, IDisposable и т. Д.) - PullRequest
0 голосов
/ 01 декабря 2011

Я пытаюсь выяснить, как контролировать, когда мои пользовательские объекты собираются сборщиком мусора - я нашел много ссылок на использование IDisposable / Destructors для этого, но в каждом примере есть что-то вроде следующего:

class Car
{
    ~Car()  // destructor
    {
        // cleanup statements...
    }
}

(http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx)

Что на самом деле происходит в «Операциях очистки»?

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

Дайте мне знать! William

Ответы [ 6 ]

2 голосов
/ 01 декабря 2011

Создавать финализатор следует только в том случае, если вам нужно очистить неуправляемые ресурсы, которые .Net не может очистить автоматически.

Вы должны внедрить IDisposable, если вам нужно очистить дорогие управляемые или неуправляемые ресурсы.Дорого не значит память;«дорогой» управляемый ресурс означает обертку вокруг чего-то неуправляемого (например, файлов, потоков, GDI + и т. д.)

Невозможно заставить GC собрать определенный объект.

1 голос
/ 01 декабря 2011

Вы не должны пытаться «контролировать ГХ», за исключением крайне редких случаев. Почти гарантировано, что вы не столкнетесь с таким случаем. Когда-либо.

IDisposable.Dispose() на самом деле (напрямую) не относится к ГХ или деструктору.

  • Dispose() - для очистки управляемых ресурсов, , кроме памяти . Это должно быть явно вызвано вашим кодом. В качестве резервной копии некоторые классы помещают вызовы в деструктор. Но это надо называть до этого.
  • Деструктор предназначен для очистки неуправляемых ресурсов, обычно также не связанных с памятью. Но вам, вероятно, следует сделать это и в Dispose().
  • ГХ запускается автоматически и хорошо выполняет свою работу - он очищает память, которую используют ваши объекты. Как правило, вы не должны с этим суетиться.
1 голос
/ 01 декабря 2011

Это зависит от того, что вы подразумеваете под «очисткой» -

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

Если вы управляете ресурсами, такими как собственные ресурсы или другие подобные концепции, которые должны быть освобождены, то IDisposable - это путь. Вы должны реализовать это должным образом, что сильно отличается от вашего примера кода. Для получения подробной информации о правильной реализации, вы можете увидеть мою серию на IDisposable .

0 голосов
/ 01 декабря 2011

Вот фрагмент кода для базового класса, который я использую для своего репозитория.Он использует интерфейс IDisposable для очистки контекста Linq-to-SQL.

    /// <summary>
/// Base class for common functionality shared across Sql repositories.
/// </summary>
internal abstract class BaseSqlRepository : IDisposable
{
    #region Members
    /// <summary>
    /// Linq to Sql data context
    /// </summary>
    private SqlRepositoryDataContext context;

    /// <summary>
    /// Determines whether the class has invoked the dispose/finalize functionality.
    /// </summary>
    private bool isDisposed;
    #endregion

    #region Constructors
    /// <summary>
    /// Initializes a new instance of the <see cref="BaseSqlRepository"/> class.
    /// </summary>
    protected BaseSqlRepository()
    {
        this.context = new SqlRepositoryDataContext(InitializeConnectionString());
        this.isDisposed = false;
    }

    protected BaseSqlRepository(SqlRepositoryDataContext Context)
    {
        this.context = Context;
        this.isDisposed = false;
    }

    /// <summary>
    /// Finalizes an instance of the BaseSqlRepository class.
    /// Releases unmanaged resources and performs other cleanup operations before the
    /// <see cref="BaseSqlRepository"/> is reclaimed by garbage collection.
    /// </summary>
    ~BaseSqlRepository()
    {
        this.Dispose(false);
    }

    #endregion

    #region Properties
    /// <summary>
    /// Gets or sets the context.
    /// </summary>
    /// <value>The context.</value>
    protected SqlRepositoryDataContext Context
    {
        get { return this.context; }
        set { this.context = value; }
    }
    #endregion

    #region Methods
    /// <summary>
    /// Initializes the connection string.
    /// </summary>
    /// <returns>Connection string.</returns>
    protected static string InitializeConnectionString()
    {
        string connectionName = ConfigurationManager.AppSettings["AppConnection"];
        string connection = string.Empty;

        if (!string.IsNullOrWhiteSpace(connectionName))
        {
            connection = ConfigurationManager.ConnectionStrings[connectionName].ConnectionString;
            if (string.IsNullOrWhiteSpace(connection))
            {
                throw new ArgumentException("Unable to initialize a connection to the database.");
            }
        }
        else
        {
            throw new ArgumentException("Unable to initialize a connection to the database.");
        }

        return connection;
    }

    /// <summary>
    /// Releases unmanaged and - optionally - managed resources
    /// </summary>
    /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
    protected void Dispose(bool disposing)
    {
        if (!this.isDisposed && disposing)
        {
            // Dispose the managed resources of the class
            this.context.Dispose();
        }

        // Dipose the un-managed resources of the class
        this.isDisposed = true;
    }

    /// <summary>
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
    /// </summary>
    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }
    #endregion
}
0 голосов
/ 01 декабря 2011

Чтобы вызвать CarInstance.Dispose(), он должен реализовать IDisposable Финализатор должен затем вызвать Dispose(false), чтобы весь код очистки находился в одном месте.

Следуйте шаблону Finalize / Dispose, указанному вэтот вопрос .

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

0 голосов
/ 01 декабря 2011

Если вы хотите контролировать, когда будет расположен конкретный объект, реализуйте для него IDisposable и вызовите obj.Dispose() явным образом.

...