0

Есть вот такой пример кода:

public void DoActions(UserClass MyClass)
{
    //Actions with MyClass
}

Как поведет себя GC если я проинициализирую UserClass прямо в аргументах метода? Т.е. :

DoActions(new UserClass());

Правильно ли я понимаю, что GC "подчистит" объект при выходе из метода/при очередной сборке мусора? А если объект будет содержать управляемый ресурс из внешней библиотеки? Достаточно ли будет реализации в UserClass метода Dispose и деконструктора для очистки этого ресурса? Т.е. например вот так:

public class UserClass : IDisposable
{
    public ClassFromExtendLibrary Memory; //Например какой-нибудь класс из внешней библиотеки реализующий внутри интерфейс IDisposable
    public int[] SomeArray;
    private bool _disposed = false;
//some code

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
    if(_disposed) return;
    if(disposing)
    {
        SomeArray = null;
        Memory?.Dispose();
    }

    _disposed = true;
}
~UserClass()
{
    Dispose(false);
}

}

Diesel
  • 11
  • Почти правильно. UMemory?.Dispose(); можно вызывать только если disposing = true. Правило: finaliser не трогает объекты .NET. Возникает вопрос: а что тогда вообще может делать finaliser? Освобождать native resources, например Marshal.FreeHGlobal. – Alex F May 19 '22 at 08:02
  • Кстати, SomeArray = null в Dispose - это лишнее, GC сам разберется с неуправляемыми объектами. – Alex F May 19 '22 at 08:05
  • Нашёл ещё хорошее объяснение здесь здесь и здесь – Diesel May 19 '22 at 08:08
  • @AlexF Благодарю за ответы. А как вызовется метод Dispose у внутреннего управляемого объекта Memory, если я не вызову Dispose у MyClass в методе DoActions, ведь финализатор его не вызовет. – Diesel May 19 '22 at 08:14
  • @AlexF Лучший вариант тогда вообще не делать инициализацию UserClass в аргументах метода DoActions()? – Diesel May 19 '22 at 08:16
  • В тему https://ru.stackoverflow.com/a/1138718/373567 – aepot May 19 '22 at 08:20
  • Если вы не вызываете Memory?.Dispose();, то Memory освободит свои ресурсы только в своем финализаторе. А это произойдет через некторое время, когда GC решит. То есть, вместо очистки ресурсов немедленно и синхронно (Dispose) вы получите очистку "через какое-то время". Все это при условии, что класс Memory реализован правильно. – Alex F May 19 '22 at 08:25
  • Теперь понял - Memory (при правильной реализации) внутри имеет неуправляемый ресурс(IntPtr) и финализатор - который и будет во внутреннем методе Dispose освобождать этот ресурс. А GC(после выхода из метода DoActions) уже сам решит когда вызвать финализатор у Memory. Благодарю @AlexF c; – Diesel May 19 '22 at 08:38

2 Answers2

2

GC "подчистит" объект при выходе из метода?

Нет, GC не триггерится при входе в метод или выходе из метода.

GC "подчистит" объект при очередной сборке мусора?

Опять же, нет. Если ссылка на объект ещё достижима, то он не будет собран.

А вот когда после выхода из метода объект станет недостижим и произойдёт сборка мусора, тогда он и будет собран.

А если объект будет содержать управляемый ресурс из внешней библиотеки? Достаточно ли будет реализации в UserClass метода Dispose и деконструктора для очистки этого ресурса?

Управляемый ресурс не нуждается в паттерне IDisposable. Он полностью подвластен сборщику мусора.

А вот неуправляемый ресурс нуждается в ручной очистке в финализаторе и/или методе Dispose.

0

GC "подчистит" объект при выходе из метода/при очередной сборке мусора

Да, но когда именно вызовется GC и вызовется ли он вообще за время работы программы - неизвестно, нет никаких гарантий его вызова.

А если объект будет содержать управляемый ресурс из внешней библиотеки?

Dispose нужно вызывать в явном виде и лучше, конечно, с помощью using (есть два варианта - со скобками и без). Автоматически он не работает.

CrazyElf
  • 71,194
  • 1
    Dispose нужно вызывать в явном виде и лучше не то, чтобы нужно, просто очень рекомендуется, если ресурс хочется освободить как можно раньше. Если все равно, когда ресурс освободится - можно это и GC доверить (главное правильно реализовать паттерн - с финализатором), но это не рекомендуемый вариант. – tym32167 May 19 '22 at 08:24