Как память была выделена и освобождена? - PullRequest
1 голос
/ 23 марта 2019

Я играю с интерфейсом IDisposable и GC, и есть кое-что, чего я не могу понять.

Итак, у нас есть следующий класс:

public class DatabaseState : IDisposable
{
    protected SqlConnection _connection;

    public virtual string GetDate()
    {
        if (_disposed)
            throw new ObjectDisposedException("DatabaseState");

        if (_connection == null)
        {
            var connectionString = ConfigurationManager.ConnectionStrings["master"];
            _connection = new SqlConnection(connectionString.ConnectionString);
            _connection.Open();
        }
        using (var command = _connection.CreateCommand())
        {
            command.CommandText = "SELECT getdate()";
            return command.ExecuteScalar().ToString();
        }
    }

    private bool _disposed;

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed)
            return;

        if (disposing)
        {
            if (_connection != null)
            {
                _connection.Dispose();
                _connection = null;
            }
            _disposed = true;
        }
    }
}

Как видите, класс довольно прост (он получает только текущую дату).

В главном у меня естьследующий код:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("'g' to Get Date; 'gc' to Garbage Collect; 'x' to Exit");
        var command = "";
        while (command != "x")
        {
            command = Console.ReadLine();
            switch (command)
            {
                case "g":
                    GetDate();
                    break;

                case "gc":
                    GC.Collect();
                    break;
            }
        }
    }

    private static void GetDate()
    {
        using (var databaseState = new DatabaseState())
        //var databaseState = new DatabaseState();
        {
            Console.WriteLine(databaseState.GetDate());
        }
    }
}

Первый эксперимент - это когда я использую IDisposable с использованием (я использовал VS build in Diagnostic Tools.)

Посмотрите на следующие снимки:

Spanshots

Число представляет идентификатор снимка.

  1. Когда я запустил приложение.Как видите, мы выделили только 29,38 КБ.
  2. Когда я ввел «g», мы выделили 245,70 КБ, что нормально.Мы открыли соединение, рукопожатие и т. Д.
  3. Когда я ввел "g" во второй раз, мы выделили только 0,55 КБ, что также должно быть нормальным.Я проверил, какой тип объекта мы создали: Hashtable, Microsoft.Win32.SafeHandles.SafeFileMappingHandle, SectionRecord и т. Д. Я не знаком с этими типами объектов и думаю, что они как-то связаны с CLR.

Отныне странные вещи происходили со мной.

4, 5,6,7 Я сделал то же самое, я нажал "g".Как видите, мы не распределили память.И это мой первый вопрос Почему? .

Я нажал «gc», что заставляет GC.Collect ().В этот момент я был удивлен.Мы не выпустили никакой памяти.Как я знаю, GC.Collect () освобождает память от всех поколений.Второй вопрос Почему GC не освободил память на этом этапе?

Я снова нажал "g".То же самое, что и на снимках 4, 5, 6 и 7. Мы не выделили никакой памяти. Почему?

10, 11 Случайно созданные снимки.

Это тоже что-то интересное.Я не делал никаких действий, и что-то выделило 2,4 КБ памяти.Я снова проверил, какие типы объектов мы создали: ContextCallback, Microsoft.Win32.SafeHandles.SafeFileMappingHandle, AppDomainPauseManager, ThreadPoolWorkQueue.И снова я не знаком с этими типами, но я думаю, что они связаны с CLR.

Так же, как 12. Я некоторое время не делал никаких действий, но на этот раз мывыпущено 20,66 кб памяти. Почему?


Подводя итог:

Насколько я понимаю, IDisposable и GC должны работать немного по-другому.В первый раз, когда я создаю экземпляр DatabaseState, я должен открыть соединение, рукопожатие и т. Д. Из-за этого мы выделим больше памяти.Из-за того, что мы используем экземпляр DatabaseState в операторе using, мы освободим эти неуправляемые ресурсы.В следующий раз, когда я использую экземпляр DatabaseState, я должен выделить немного памяти (но, как я видел из снимков 4,5,6,7 и 9, я не выделил никакой памяти) только для экземпляра, потому что соединение, рукопожатие ужебыло сделано.

Я что-то упустил, но я не знаю, что и где.

С уважением

...