Я играю с интерфейсом 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.)
Посмотрите на следующие снимки:
Число представляет идентификатор снимка.
- Когда я запустил приложение.Как видите, мы выделили только 29,38 КБ.
- Когда я ввел «g», мы выделили 245,70 КБ, что нормально.Мы открыли соединение, рукопожатие и т. Д.
- Когда я ввел "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, я не выделил никакой памяти) только для экземпляра, потому что соединение, рукопожатие ужебыло сделано.
Я что-то упустил, но я не знаю, что и где.
С уважением