언제 GC.SuppressFinalize ()를 사용해야합니까?


287

.NET에서 어떤 상황에서 사용해야 GC.SuppressFinalize()합니까?

이 방법을 사용하면 어떤 이점이 있습니까?


나는 파이 나라와는 IDisposable에 대한 몇 가지 질문을 보았다, 유래는 GC.SupressFinalize 약한 참조에 대해 뭔가가 있어야합니다
샘 사프란

나는 약한 레퍼런스가 파이널 라이저와 관련하여 많은 일을한다고 생각하지 않습니다. 아마도 더 직접적인 질문을 게시해야합니다.
Michael Burr

Yerp I는 약한 심판에 대한 별도의 질문을 게시하는 것을 의미했습니다.이 모든 것은 객체 풀을 만들 때 함께 묶을 수 있습니다. 또한 ReRegisterForFinalize
Sam Saffron의

답변:


296

SuppressFinalize종료자가있는 클래스에서만 호출해야합니다. 가비지 콜렉터 (GC)에 this오브젝트가 완전히 정리 되었음을 알리고 있습니다.

종료자가 IDisposable있을 때 권장되는 패턴은 다음과 같습니다.

public class MyClass : IDisposable
{
    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // called via myClass.Dispose(). 
                // OK to use any private object references
            }
            // Release unmanaged resources.
            // Set large fields to null.                
            disposed = true;
        }
    }

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

    ~MyClass() // the finalizer
    {
        Dispose(false);
    }
}

일반적으로 CLR은 객체를 만들 때 종료자가있는 객체의 탭을 유지하므로 생성하는 데 비용이 많이 듭니다. SuppressFinalizeGC에 개체가 올바르게 정리되었으며 종료 자 대기열로 이동할 필요가 없음을 알려줍니다. C ++ 소멸자처럼 보이지만 하나처럼 행동하지는 않습니다.

SuppressFinalize당신의 객체가 종료 자 큐에서 대기하는 시간이 오래 살 수있는 최적화, 사소한하지 않습니다. SuppressFinalize다른 물건을 생각하고 싶은 유혹을 느끼지 마십시오 . 그것은 심각한 결함이 일어나기를 기다리고 있습니다.

디자인 지침은 객체가 구현하는 경우 종료자가 필요하지 않다고 알려주지 IDisposable만 종료자가 있으면 IDisposable클래스를 결정적으로 정리할 수 있도록 구현해야 합니다.

대부분의 경우 IDisposable리소스 정리 를 위해 벗어날 수 있어야 합니다. 개체가 관리되지 않는 리소스를 보유하고 있고 해당 리소스가 정리되도록 보장해야 할 경우에만 종료자가 필요합니다.

참고 : 때때로 코더는 IDisposable코드가 IDisposable객체를 올바르게 배치했는지 테스트하기 위해 자체 클래스의 빌드를 디버깅 하기 위해 종료자를 추가합니다 .

public void Dispose() // Implement IDisposable
{
    Dispose(true);
#if DEBUG
    GC.SuppressFinalize(this);
#endif
}

#if DEBUG
~MyClass() // the finalizer
{
    Dispose(false);
}
#endif

1
첫 번째 코드 스 니펫에서는 권장 IDisposable + finalizer 패턴이 어떻게 보이는지 게시하고 있습니다. 코드 디버깅은 좋지만주의가 산만해질 수 있습니다. .. 관리되지 않는 리소스가있는 클래스를 제외하고는 종료자를 피하는 것이 좋습니다. 안전한 종료 코드를 작성하는 것은 쉽지 않습니다.
Robert Paulson

1
안녕하세요, finalizer의 매개 변수로 false를 사용하여 dispose를 호출해야하는 이유는 무엇입니까? 처분이 호출되지 않은 다음 처분하지 않으면 어떻게됩니까? 객체가 폐기되었는지 여부를 확인하고 실제 정리를 수행하면 어떨까요?
Dreamer

3
@Dreamer-구현에 따라 다릅니다. 일반적으로 Finalizer가 Dispose를 호출하는지 여부와 IDisposable.Dispose () 구현을 알고 싶습니다. 종료 자에서 호출되면 개인 참조가 더 이상 유효하지 않으며 실제로 많은 것을 할 수 없다고 가정해야합니다. 그러나 IDisposable.Dispose ()에서 호출 된 경우 참조가 여전히 유효하다는 것을 알고 있습니다.
Robert Paulson

32
클래스 구현 IDisposable이 아닌 경우 사용자 정의 종료sealed 자를 GC.SuppressFinalize(this) 포함하지 않더라도 호출을 포함해야합니다 . 이는 사용자 정의 종료자를 추가하지만 보호 된 Dispose(bool)메서드 만 재정의하는 파생 형식에 대한 적절한 의미 체계를 보장하기 위해 필요합니다 .
Sam Harwell

1
sealed파생 클래스에는 @SamHarwell에서 언급 하지 않은 것이 중요합니다. 클래스가 봉인되지 않은 경우 CodeAnalysis에서 ca1816 + ca1063이 발생하지만 봉인 된 클래스는 SuppressFinalize.
dashesy

38

SupressFinalize파이널 라이저에서 수행 된 작업이 이미 완료되었음을 시스템에 알려주므로 파이널 라이저를 호출 할 필요가 없습니다. .NET 문서에서 :

IDisposable 인터페이스를 구현하는 객체는 IDisposable.Dispose 메서드에서이 메서드를 호출하여 가비지 수집기가 Object.Finalize를 필요로하지 않는 개체에서 호출하지 못하게합니다.

일반적으로 finalizer에서 정리할 모든 항목을 정리해야하므로 대부분의 Dispose()메소드는을 호출 할 수 있어야합니다 GC.SupressFinalize().

SupressFinalize시스템이 객체를 종료 자 스레드에 큐잉하지 않도록하는 최적화를 제공하는 것입니다. 제대로 작성된 Dispose()/ 완료자는에 대한 호출 여부에 관계없이 제대로 작동해야합니다 GC.SupressFinalize().


2

이 메소드는 Dispose을 구현하는 객체 의 메소드에서 호출되어야합니다 IDisposable. 이런 식으로 누군가가 Dispose메소드를 호출하면 GC가 종료자를 다시 호출하지 않습니다 .

참조 : GC.SuppressFinalize (Object) 메서드-Microsoft Docs


9
"필수"가 아니라 "필수"라고 생각합니다. 일부 시나리오에서는 객체 큐잉 / 완료 오버 헤드를 제거 할 수 있습니다.
기본

1
Dispose(true);
GC.SuppressFinalize(this);

object에 finalizer가 있으면 .net은 finalization queue에 참조를 넣습니다.

우리는 call을 가지고 있기 때문에 Dispose(ture)객체를 지우 므로이 작업을 수행하기 위해 종료 대기열이 필요하지 않습니다.

따라서 GC.SuppressFinalize(this)종료 큐에서 참조 제거를 호출 하십시오.


0

클래스 또는 클래스에서 파생 된 클래스가 종료자를 사용하여 오브젝트에 대한 마지막 실시간 참조를 보유 할 수있는 경우, 종료 자에 의해 부정적인 영향을받을 수있는 조작 후 오브젝트에서 호출 GC.SuppressFinalize(this)되거나 종료 GC.KeepAlive(this)되어야합니다. 해당 작업이 완료 될 때까지 실행하지 마십시오.

비용 GC.KeepAlive()과는 GC.SuppressFinalize(this)본질적으로 파이널이없는 그 모든 클래스에서 동일, 일반적으로 호출해야 파이 나라가 할 클래스 GC.SuppressFinalize(this)그래서 마지막 단계로 후자의 기능을 사용하여 Dispose()항상 필요하지 않을 수도 있습니다,하지만 그것은하지 않습니다 틀리다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.