문제

.NET 가비지 수집기는 결국 메모리를 확보하지만 해당 메모리를 즉시 되찾고 싶다면 어떻게 해야 할까요?수업에 어떤 코드를 사용해야 합니까? MyClass 전화하다

MyClass.Dispose()

변수와 객체에 의해 사용된 모든 공간을 확보합니다. MyClass?

도움이 되었습니까?

해결책

IDisposable은 메모리 해제와 관련이 없습니다.IDisposable은 해제를 위한 패턴입니다. 관리되지 않는 리소스 - 그리고 메모리는 확실히 관리되는 리소스입니다.

GC.Collect()를 가리키는 링크가 정답이지만 Microsoft .NET 설명서에서는 일반적으로 이 함수의 사용을 권장하지 않습니다.

편집하다: 이 답변에 대해 상당한 양의 카르마를 얻었으므로 .NET 리소스 관리를 처음 접하는 사람이 잘못된 인상을 받지 않도록 이에 대해 자세히 설명해야 한다는 책임감을 느낍니다.

.NET 프로세스 내에는 관리형과 비관리형이라는 두 가지 종류의 리소스가 있습니다."관리형"은 런타임이 리소스를 제어한다는 의미이고 "관리형"은 프로그래머의 책임임을 의미합니다.그리고 오늘날 .NET에서 우리가 관심을 갖는 관리형 리소스는 메모리라는 한 종류뿐입니다.프로그래머는 런타임에 메모리를 할당하라고 지시한 후 메모리가 언제 해제될 수 있는지 파악하는 것은 런타임에 달려 있습니다..NET에서 이 목적으로 사용하는 메커니즘을 쓰레기 수거 그리고 인터넷에서 구글을 이용하면 GC에 관한 많은 정보를 쉽게 찾을 수 있습니다.

다른 종류의 리소스의 경우 .NET은 정리에 대해 아무것도 모르므로 올바른 작업을 수행하려면 프로그래머에게 의존해야 합니다.이를 위해 플랫폼은 프로그래머에게 세 가지 도구를 제공합니다.

  1. VB 및 C#의 IDisposable 인터페이스와 "using" 문
  2. 종료자
  3. 많은 BCL 클래스에 의해 구현되는 IDisposable 패턴

첫 번째 방법을 사용하면 프로그래머가 리소스를 효율적으로 획득하고 사용하고 동일한 방법 내에서 모두 해제할 수 있습니다.

using (DisposableObject tmp = DisposableObject.AcquireResource()) {
    // Do something with tmp
}
// At this point, tmp.Dispose() will automatically have been called
// BUT, tmp may still a perfectly valid object that still takes up memory

예를 들어 "AcquireResource"가 파일을 여는 팩토리 메서드이고 "Dispose"가 자동으로 파일을 닫는 경우 이 코드는 파일 리소스를 누출할 수 없습니다.그러나 "tmp" 개체 자체에 대한 메모리는 여전히 할당될 수 있습니다.그 이유는 IDisposable 인터페이스가 가비지 수집기와 전혀 연결되어 있지 않기 때문입니다.만약 너라면 했다 메모리가 해제되었는지 확인하려는 경우 유일한 옵션은 다음을 호출하는 것입니다. GC.Collect() 가비지 수집을 강제합니다.

그러나 이것이 아마도 좋은 생각이 아닐 수도 있다는 점은 아무리 강조해도 지나치지 않습니다.일반적으로 가비지 수집기가 원래 의도한 대로 메모리를 관리하도록 하는 것이 훨씬 더 좋습니다.

리소스가 장기간 사용되어 수명이 여러 가지 방법에 걸쳐 발생하면 어떻게 되나요?분명히 "using" 문은 더 이상 적용할 수 없으므로 프로그래머는 리소스 사용이 끝나면 수동으로 "Dispose"를 호출해야 합니다.프로그래머가 잊어버리면 어떻게 될까요?대체가 없으면 프로세스나 컴퓨터는 결국 제대로 해제되지 않은 리소스가 부족해질 수 있습니다.

이것이 종료자가 들어오는 곳입니다.종료자는 가비지 수집기와 특별한 관계가 있는 클래스의 메서드입니다.GC는 해당 유형의 개체에 대한 메모리를 해제하기 전에 먼저 종료자에게 일종의 정리 작업을 수행할 수 있는 기회를 제공할 것을 약속합니다.

따라서 파일의 경우 이론적으로는 파일을 수동으로 닫을 필요가 전혀 없습니다.가비지 수집기가 도착할 때까지 기다렸다가 종료자가 작업을 수행하도록 하면 됩니다.불행하게도 가비지 수집기가 비결정적으로 실행되기 때문에 실제로는 제대로 작동하지 않습니다.파일은 프로그래머가 예상하는 것보다 상당히 오랫동안 열려 있을 수 있습니다.그리고 충분한 파일이 열려 있으면 추가 파일을 열려고 할 때 시스템이 실패할 수 있습니다.

대부분의 리소스에서 우리는 이 두 가지를 모두 원합니다.우리는 "이제 이 리소스는 끝났습니다"라고 말할 수 있는 규칙을 원하며, 수동으로 수행하는 것을 잊어버린 경우 정리가 자동으로 발생할 가능성이 최소한 어느 정도 있는지 확인하고 싶습니다.이것이 바로 "IDisposable" 패턴이 적용되는 부분입니다.이는 IDispose와 종료자가 함께 원활하게 작동할 수 있도록 하는 규칙입니다.패턴을 보면 패턴이 어떻게 작동하는지 알 수 있습니다. IDisposable 공식 문서.

요점: 정말로 원하는 것이 메모리가 해제되었는지 확인하는 것이라면 IDisposable과 종료자는 도움이 되지 않습니다.그러나 IDisposable 인터페이스는 모든 .NET 프로그래머가 이해해야 하는 매우 중요한 패턴의 일부입니다.

다른 팁

IDisposable 인터페이스를 구현하는 인스턴스만 삭제할 수 있습니다.

가비지 수집을 통해 (관리되지 않는) 메모리를 즉시 확보하려면 다음 안내를 따르세요.

GC.Collect();  
GC.WaitForPendingFinalizers();

이는 일반적으로 나쁜 습관이지만, 예를 들어 일부 시나리오에서 GC가 이상하게 동작하게 만드는 .NET Framework의 x64 버전에 버그가 있으므로 이를 수행할 수 있습니다.아직 버그가 해결되었는지는 모르겠습니다.아는 사람 있나요?

클래스를 삭제하려면 다음을 수행합니다.

instance.Dispose();

또는 다음과 같습니다:

using(MyClass instance = new MyClass())
{
    // Your cool code.
}

컴파일 타임에 다음과 같이 변환됩니다.

MyClass instance = null;    

try
{
    instance = new MyClass();        
    // Your cool code.
}
finally
{
    if(instance != null)
        instance.Dispose();
}

다음과 같이 IDisposable 인터페이스를 구현할 수 있습니다.

public class MyClass : IDisposable
{
    private bool disposed;

    /// <summary>
    /// Construction
    /// </summary>
    public MyClass()
    {
    }

    /// <summary>
    /// Destructor
    /// </summary>
    ~MyClass()
    {
        this.Dispose(false);
    }

    /// <summary>
    /// The dispose method that implements IDisposable.
    /// </summary>
    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// The virtual dispose method that allows
    /// classes inherithed from this one to dispose their resources.
    /// </summary>
    /// <param name="disposing"></param>
    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Dispose managed resources here.
            }

            // Dispose unmanaged resources here.
        }

        disposed = true;
    }
}

이 질문에 대한 답변은 다소 혼란스럽습니다.

제목은 폐기에 대해 묻지만 즉시 메모리를 되찾기를 원한다고 말합니다.

.Net은 관리하다, 즉, .Net 앱을 작성할 때 메모리에 대해 직접적으로 걱정할 필요가 없으며 비용도 메모리를 직접 제어할 수 없다는 의미입니다.

.Net은 .Net 코더가 아닌 메모리를 정리하고 해제하는 것이 가장 좋은 시기를 결정합니다.

그만큼 Dispose 는 .Net에 작업이 완료되었음을 알리는 방법이지만 가장 적절한 시점이 될 때까지 실제로 메모리를 확보하지는 않습니다.

기본적으로 .Net은 가장 쉬운 시점에 실제로 메모리를 다시 수집합니다. 시기를 결정하는 데 매우 유용합니다.매우 메모리 집약적인 무언가를 작성하지 않는 한 일반적으로 이를 무시할 필요가 없습니다. (이것이 게임이 아직 .Net으로 작성되지 않는 이유 중 하나입니다. 완전한 제어가 필요합니다.)

.Net에서는 다음을 사용할 수 있습니다. GC.Collect() 즉시 강제로 실행하지만 이는 거의 항상 나쁜 습관입니다..Net이 아직 정리하지 않은 경우 이는 정리하기에 특히 좋은 시기가 아니라는 의미입니다.

GC.Collect() .Net이 완료되었다고 식별하는 객체를 선택합니다.필요한 개체를 삭제하지 않은 경우 .Net은 해당 개체를 유지하기로 결정할 수 있습니다.이는 다음을 의미합니다. GC.Collect() 일회용 인스턴스를 올바르게 구현한 경우에만 효과적입니다.

GC.Collect() ~이다 ~ 아니다 IDisposable을 올바르게 사용하기 위한 대체품입니다.

따라서 Dispose와 메모리는 직접적인 관련이 없지만 반드시 그럴 필요도 없습니다.올바르게 폐기하면 .Net 앱이 더 효율적이게 되므로 메모리를 덜 사용하게 됩니다.


.Net에서는 99%의 경우 다음이 모범 사례입니다.

규칙 1: 아무 것도 다루지 않으면 관리되지 않는 또는 구현하는 것 IDisposable 그렇다면 Dispose에 대해 걱정하지 마세요.

규칙 2: IDisposable을 구현하는 지역 변수가 있는 경우 현재 범위에서 이를 제거해야 합니다.

//using is best practice
using( SqlConnection con = new SqlConnection("my con str" ) )
{
    //do stuff
} 

//this is what 'using' actually compiles to:
SqlConnection con = new SqlConnection("my con str" ) ;
try
{
    //do stuff
}
finally
{
    con.Dispose();
}

규칙 3: 클래스에 IDisposable을 구현하는 속성이나 멤버 변수가 있는 경우 해당 클래스도 IDisposable을 구현해야 합니다.해당 클래스의 Dispose 메서드에서 IDisposable 속성을 삭제할 수도 있습니다.

//rather basic example
public sealed MyClass :
   IDisposable
{   
    //this connection is disposable
    public SqlConnection MyConnection { get; set; }

    //make sure this gets rid of it too
    public Dispose() 
    {
        //if we still have a connection dispose it
        if( MyConnection != null )
            MyConnection.Dispose();

        //note that the connection might have already been disposed
        //always write disposals so that they can be called again
    }
}

이는 실제로 완전하지 않으므로 예제가 봉인된 것입니다.상속받는 클래스는 다음 규칙을 준수해야 할 수도 있습니다...

규칙 4: 클래스가 관리되지 않는 리소스를 구현한 다음 IDispose를 구현합니다. 그리고 종료자를 추가합니다.

.Net은 아무것도 할 수 없습니다 관리되지 않는 자원, 이제 우리는 메모리에 대해 이야기하고 있습니다.정리하지 않으면 메모리 누수가 발생할 수 있습니다.

Dispose 메서드는 두 가지를 모두 처리해야 합니다. 관리하다 그리고 관리되지 않는 자원.

종료자는 안전 장치입니다. 다른 사람이 클래스의 인스턴스를 생성하고 처리하지 못한 경우 '위험한' 클래스임을 보장합니다. 관리되지 않는 리소스는 여전히 .Net으로 정리될 수 있습니다.

~MyClass()
{
    //calls a protected method 
    //the false tells this method
    //not to bother with managed
    //resources
    this.Dispose(false);
}

public void Dispose()
{
    //calls the same method
    //passed true to tell it to
    //clean up managed and unmanaged 
    this.Dispose(true);

    //as dispose has been correctly
    //called we don't need the 

    //'backup' finaliser
    GC.SuppressFinalize(this);
}

마지막으로 부울 플래그를 사용하는 Dispose 오버로드는 다음과 같습니다.

protected virtual void Dispose(bool disposing)
{
    //check this hasn't been called already
    //remember that Dispose can be called again
    if (!disposed)
    {
        //this is passed true in the regular Dispose
        if (disposing)
        {
            // Dispose managed resources here.
        }

        //both regular Dispose and the finaliser
        //will hit this code
        // Dispose unmanaged resources here.
    }

    disposed = true;
}

이 모든 것이 완료되면 클래스의 인스턴스를 생성하는 다른 관리 코드는 이를 다른 IDisposable처럼 처리할 수 있습니다(규칙 2 및 3).

dispose가 항상 메모리를 참조하는 것은 아니라는 점도 언급하는 것이 적절할까요?나는 메모리보다 파일에 대한 참조와 같은 리소스를 더 자주 폐기합니다.GC.Collect()는 CLR 가비지 수집기와 직접 관련되며 작업 관리자에서 메모리를 확보할 수도 있고 확보하지 못할 수도 있습니다.이는 애플리케이션에 부정적인 방식(예: 성능)으로 영향을 미칠 가능성이 높습니다.

하루가 끝나면 왜 즉시 기억을 되찾기를 원합니까?다른 곳에서 메모리 압박이 있는 경우 대부분의 경우 OS가 메모리를 제공합니다.

이것을보세요 기사

Dispose 패턴, IDisposable 및/또는 종료자를 구현하는 것은 메모리가 회수되는 시기와 전혀 관련이 없습니다.대신 GC에 알리는 것과 모든 관련이 있습니다. 어떻게 그 기억을 되찾기 위해.Dispose()를 호출하면 GC와 상호 작용하지 않습니다.

GC는 필요하다고 판단되는 경우(메모리 부족이라고 함)에만 실행되며 그런 다음에만 사용되지 않는 개체에 대한 메모리 할당을 해제하고 메모리 공간을 압축합니다.

~할 수 있었다 GC.Collect()를 호출하지만 실제로는 매우 그럴 만한 이유가 있습니다(거의 항상 "절대"임).이와 같이 대역 외 수집 주기를 강제로 적용하면 실제로 GC가 더 많은 작업을 수행하게 되고 궁극적으로 애플리케이션 성능이 저하될 수 있습니다.GC 수집 주기 동안 애플리케이션은 실제로 정지 상태에 있습니다. GC 주기를 더 많이 실행할수록 애플리케이션이 정지되는 데 더 많은 시간이 소요됩니다.

작업 세트를 해제하기 위해 수행할 수 있는 몇 가지 기본 Win32 API 호출도 있지만 특별한 경우가 아니면 이러한 호출도 피해야 합니다. 매우 그렇게 하는 데에는 좋은 이유가 있습니다.

가비지 수집 런타임의 전제는 런타임이 실제 메모리를 할당/할당 취소하는 시기에 대해 걱정할 필요가 없다는 것입니다.당신의 객체가 요청을 받았을 때 스스로 정리하는 방법을 알고 있는지 확인하는 것에 대해서만 걱정하면 됩니다.

public class MyClass : IDisposable
{
    public void Dispose()
    {
       // cleanup here
    }
}

그럼 넌 이런 걸 할 수 있어

MyClass todispose = new MyClass();
todispose.Dispose(); // instance is disposed right here

또는

using (MyClass instance = new MyClass())
{

}
// instance will be disposed right here as it goes out of scope

"에 대한 Joe Duffy의 전체 설명폐기, 마무리 및 자원 관리":

.NET Framework의 수명 초기에 Finalizers는 C# 프로그래머에 의해 지속적으로 소멸자라고합니다.시간이 지남에 따라 더 똑똑해지면서 우리는 Dispose Method는 C ++ Destructor (결정 론적)와 실제로 더 동등합니다., 반면 Finalizer는 완전히 분리 된 것입니다 (비 결정적).C#이 C ++ 소멸자 구문을 빌렸다는 사실 (예 :~ t ())는이 잘못된 이름의 발달과 적어도 조금 관련이있었습니다.

나는 소멸자와 처리 및 가비지 수집에 대한 요약을 썼습니다. http://codingcraftsman.wordpress.com/2012/04/25/to-dispose-or-not-to-dispose/

원래 질문에 대답하려면 다음을 수행하십시오.

  1. 기억을 관리하려고 하지 마세요
  2. Dispose는 메모리 관리가 아니라 관리되지 않는 리소스 관리에 관한 것입니다.
  3. 종료자는 Dispose 패턴의 기본 부분이며 실제로 관리되는 개체의 메모리 해제 속도를 늦춥니다(아직 Dispose d가 아닌 이상 종료 대기열로 이동해야 하기 때문).
  4. GC.Collect는 일부 단기 개체가 더 오랫동안 필요한 것처럼 보이게 만들어 수집 속도를 늦추기 때문에 좋지 않습니다.

그러나 코드의 성능이 중요한 부분이 있고 가비지 수집으로 인해 속도가 느려질 가능성을 줄이려는 경우 GC.Collect가 유용할 수 있습니다.당신은 전에 그것을 호출합니다.

게다가 이 패턴을 지지하는 주장도 있습니다:

var myBigObject = new MyBigObject(1);
// something happens
myBigObject = new MyBigObject(2);
// at the above line, there are temporarily two big objects in memory and neither can be collected

myBigObject = null; // so it could now be collected
myBigObject = new MyBigObject(2);

하지만 주된 대답은 가비지 수집이 사용자가 조작하지 않는 한 제대로 작동한다는 것입니다!

GC가 원할 때 개체를 정리하도록 강제할 수는 없습니다. 강제로 실행하는 방법이 있지만 원하는/예상하는 모든 개체를 정리한다고는 말할 수 없습니다.try catch ex finally dispose end try(VB.NET rulz) 방식으로 dispose를 호출하는 것이 가장 좋습니다.하지만 Dispose는 시스템 리소스(메모리, 핸들, DB 연결 등)를 정리하는 데 사용됩니다.결정론적인 방식으로 객체에 의해 할당됩니다.Dispose는 개체 자체에서 사용하는 메모리를 정리하지 않으며 정리할 수도 없습니다. GC만이 이를 수행할 수 있습니다.

이 기사 매우 간단한 연습이 있습니다.하지만, 자연스러운 과정을 거치지 않고 GC를 호출하는 것은 일반적으로 잘못된 디자인/메모리 관리의 신호입니다. 특히 제한된 리소스가 사용되지 않는 경우(연결, 핸들, 일반적으로 IDisposable 구현으로 이어지는 기타 모든 것)

이 작업을 수행해야 하는 이유는 무엇입니까?

죄송합니다. 여기서 선택한 답변이 올바르지 않습니다.몇몇 사람들이 나중에 언급했듯이 IDisposable을 Dispose하고 구현하는 것은 .NET 클래스와 관련된 메모리를 해제하는 것과 아무 관련이 없습니다.이는 주로 파일 핸들 등과 같은 관리되지 않는 리소스를 해제하는 데 사용됩니다.

애플리케이션이 GC.Collect()를 호출하여 가비지 수집기에 의한 수집을 강제로 시도할 수 있지만 이는 실제로는 연결 가능한 대기열에서 올바른 생성 수준에 있는 항목에만 영향을 미칩니다.따라서 객체에 대한 모든 참조를 지운 경우에도 실제 메모리가 해제되기 전에 GC.Collect()에 대한 몇 번의 호출이 남아 있을 수 있습니다.

질문에 왜 즉시 메모리를 확보해야 한다고 생각하는지 말하지 않았습니다.때로는 비정상적인 상황이 있을 수 있다는 점을 이해하지만, 관리되는 코드에서는 거의 항상 런타임에서 메모리 관리를 처리하도록 하는 것이 가장 좋습니다.

아마도 코드가 GC가 메모리를 해제하는 것보다 메모리를 더 빨리 소모한다고 생각한다면 가장 좋은 조언일 것입니다. 그러면 코드를 검토하여 정적 멤버 등에 있는 데이터 구조에서 더 이상 필요하지 않은 개체가 참조되지 않는지 확인해야 합니다. .또한 순환 개체 참조가 해제되지 않을 수도 있으므로 이러한 상황을 피하십시오.

@키이스,

#4를 제외한 모든 규칙에 동의합니다.종료자를 추가하는 것은 매우 특정한 상황에서만 수행되어야 합니다.클래스가 관리되지 않는 리소스를 사용하는 경우 Dispose(bool) 함수에서 해당 리소스를 정리해야 합니다.이 동일한 함수는 bool이 true인 경우에만 관리되는 리소스를 정리해야 합니다.종료자를 추가하면 새 인스턴스를 생성할 때마다 GC가 수집 주기를 실행할 때마다 확인되는 종료 큐에 배치되어야 하므로 개체 사용에 복잡성 비용이 추가됩니다.효과적으로 이는 종료자가 실행될 수 있도록 개체가 필요한 것보다 한 주기/세대 더 오래 생존한다는 것을 의미합니다.종료자를 "안전망"으로 생각하면 안 됩니다.

GC는 대역 외 수집을 강제하기 위해 GC.Collect()를 호출하여 "도움"을 제공하지 않는 한 Gen0 힙에 다음 할당을 수행할 수 있는 사용 가능한 메모리가 충분하지 않다고 판단한 경우에만 수집 주기를 실행합니다. .

결론은 무슨 일이 있어도 GC는 Dispose 메서드(구현된 경우 종료자도 가능)를 호출하여 리소스를 해제하는 방법만 알고 있다는 것입니다."올바른 일을 수행"하고 사용된 관리되지 않는 리소스를 정리하고 다른 관리되는 리소스에 Dispose 메서드를 호출하도록 지시하는 것은 해당 메서드에 달려 있습니다.이는 수행하는 작업이 매우 효율적이며 대역 외 수집 주기의 도움을 받지 않는 한 자체 최적화가 가능합니다.즉, GC.Collect를 명시적으로 호출하지 않으면 객체가 언제, 어떤 순서로 삭제되고 메모리가 해제되는지 제어할 수 없습니다.

MyClass가 IDisposable을 구현하면 그렇게 할 수 있습니다.

MyClass.Dispose();

C#의 모범 사례는 다음과 같습니다.

using( MyClass x = new MyClass() ) {
    //do stuff
}

이렇게 하면 try-finally에서 처리가 마무리되고 절대 누락되지 않는지 확인됩니다.

클래스에 IDisposable을 구현하고 싶지 않거나 구현할 수 없는 경우 다음과 같이 가비지 수집을 강제로 수행할 수 있습니다(하지만 속도가 느림).

GC.Collect();

IDisposable 인터페이스는 실제로 관리되지 않는 리소스가 포함된 클래스를 위한 것입니다.클래스에 관리되지 않는 리소스가 포함되어 있지 않은 경우 이유는 무엇입니까? 필요 가비지 수집기가 리소스를 확보하기 전에 리소스를 확보하려면 어떻게 해야 할까요?그렇지 않으면 개체가 가능한 한 늦게 인스턴스화되고 최대한 빨리 범위를 벗어나는지 확인하세요.

C++에서는 결정론적 개체 파괴가 가능합니다.

GC.Collect를 호출하고 싶지 않을 경우 가비지 수집기의 자체 조정을 방해하여 메모리 부족을 감지하고 어떤 경우에는 힙에 있는 모든 개체의 현재 생성을 늘리는 것 외에는 아무것도 수행하지 않습니다.

IDisposable 답변을 게시하는 사람들을 위해.Dispose 메서드를 호출해도 질문자가 설명한 대로 개체가 삭제되지 않습니다.

@키이스:

IDisposable은 관리형 리소스용입니다.

종료자는 관리되지 않는 리소스를 위한 것입니다.

죄송하지만 그건 틀렸어요.일반적으로 종료자는 아무 작업도 수행하지 않습니다.그러나 만약 패턴을 폐기하다 올바르게 구현되었으면 종료자는 호출을 시도합니다. Dispose.

Dispose 두 가지 직업이 있습니다:

  • 관리되지 않는 리소스를 무료로 제공합니다.
  • 중첩된 관리 리소스를 무료로 제공합니다.

마무리하는 동안 개체는 중첩된 관리 리소스가 이미 해제되었을 수 있으므로 해제하려고 시도해서는 안 된다는 것이 사실이기 때문에 여기에서 귀하의 진술이 적용됩니다.그래도 관리되지 않는 리소스를 해제해야 합니다.

그래도 finalizer는 호출하는 것 외에는 할 일이 없습니다. Dispose 관리되는 개체를 건드리지 말라고 지시합니다. Dispose, 수동으로 호출할 때(또는 다음을 통해 Using), 관리되지 않는 모든 리소스를 해제하고 다음을 통과해야 합니다. Dispose 중첩된 개체(및 기본 클래스 메서드)에 메시지를 보내지만 이는 절대 (관리되는) 메모리를 해제합니다.

Konrad Rudolph - 그렇습니다. 일반적으로 종료자는 아무것도 하지 않습니다.관리되지 않는 리소스를 다루지 않는 한 이를 구현해서는 안 됩니다.

그런 다음 이를 구현할 때 다음을 사용합니다. Microsoft의 폐기 패턴 (이미 설명한 대로)

  • public Dispose() 전화 protected Dispose(true) - 관리되는 자원과 관리되지 않는 자원을 모두 다룹니다.부름 Dispose() 마무리를 억제해야합니다.

  • ~Finalize 전화 protected Dispose(false) - 관리되지 않는 리소스만 다룹니다.이렇게 하면 호출에 실패할 경우 관리되지 않는 메모리 누수를 방지할 수 있습니다. public Dispose()

~Finalize 속도가 느리므로 처리할 관리되지 않는 리소스가 없는 한 사용하면 안 됩니다.

관리형 리소스는 메모리 누수를 방지하며 현재 애플리케이션의 리소스만 낭비하고 가비지 수집 속도를 늦출 수 있습니다.관리되지 않는 리소스가 누출될 수 있으며, ~Finalize 발생하지 않도록 하는 것이 가장 좋은 방법입니다.

두 경우 모두 using 모범 사례입니다.

@Curt Hagenlocher - 뒤에서 앞으로입니다.그것이 틀렸는데 왜 그렇게 많은 사람들이 투표했는지 모르겠습니다.

IDisposable 이다 관리하다 자원.

최종화자는 다음을 대상으로 합니다. 관리되지 않는 자원.

관리되는 리소스만 사용하는 한 @Jon Limjap과 나 모두 완전히 정확합니다.

관리되지 않는 리소스를 사용하는 클래스의 경우(그리고 대부분의 .Net 클래스는 그렇지 않다는 점을 염두에 두십시오) Patrik의 답변은 포괄적이고 모범 사례입니다.

GC.Collect 사용을 피하세요. 이는 관리되는 리소스를 처리하는 느린 방법이며, ~Finalizer를 올바르게 구축하지 않는 한 관리되지 않는 리소스에 대해서는 아무 작업도 수행하지 않습니다.


나는 원래 질문에서 중재자의 의견을 삭제했습니다. https://stackoverflow.com/questions/14593/etiquette-for-modifying-posts

원래 질문에 대한 답변에서 원래 포스터가 지금까지 제공한 정보를 보면 그가 .NET 프로그래밍에 대해 충분히 알지 못해 답변을 받을 수 없다는 것이 100% 확실합니다.GC.Collect()를 사용하세요.대부분의 포스터에서 지적했듯이 그가 실제로 GC.Collect()를 전혀 사용할 필요가 없을 가능성이 99.99%라고 말하고 싶습니다.

정답은 'GC가 작업을 수행하도록 하세요'로 요약됩니다.기간.걱정할 다른 것들이 있습니다.그러나 특정 개체를 삭제하거나 정리해야 하는지 여부와 시기, 클래스에서 IDisposable 및 Finalize를 구현해야 하는지 여부를 고려해야 할 수도 있습니다.'

Keith의 게시물과 그의 규칙 #4에 관해:

일부 포스터에서는 규칙 3과 규칙 4를 혼동하고 있습니다.Keith의 규칙 4는 절대적으로 정확합니다.편집이 전혀 필요하지 않은 네 가지 규칙 중 하나입니다.나는 그의 다른 규칙 중 일부를 좀 더 명확하게 설명하기 위해 약간 다시 설명하겠지만, 올바르게 구문 분석하고 실제로 전체 게시물을 읽어 그가 규칙을 어떻게 확장하는지 확인한다면 규칙은 본질적으로 정확합니다.

  1. 클래스가 관리되지 않는 리소스를 사용하지 않고 직접적으로 또는 궁극적으로 관리되지 않는 개체(예: IDisposable을 구현하는 클래스)를 사용하는 클래스의 다른 개체를 인스턴스화하지 않는 경우 클래스가 필요하지 않습니다. IDisposable 자체를 구현하거나 무엇이든 .dispose를 호출할 수도 있습니다.(이런 경우 강제 GC를 통해 메모리를 즉시 확보해야 한다고 생각하는 것은 어리석은 일입니다.)

  2. 클래스가 관리되지 않는 리소스를 사용하거나 자체적으로 IDisposable을 구현하는 다른 개체를 인스턴스화하는 경우 클래스는 다음 중 하나를 수행해야 합니다.

    a) 해당 항목이 생성된 로컬 컨텍스트에서 즉시 삭제/해제하거나...

    b) Keith의 게시물이나 인터넷의 수천 곳, 문자 그대로 약 300권의 책에서 권장되는 패턴으로 IDisposable을 구현합니다.

    b.1) 또한 (b)가 열려 있는 관리되지 않는 리소스인 경우 Keith의 규칙 #4에 따라 IDisposable과 Finalize가 항상 구현되어야 합니다.
    이러한 맥락에서 Finalize는 어떤 의미에서 절대적으로 안전망입니다.누군가 관리되지 않는 리소스를 사용하는 IDisposable 개체를 인스턴스화하고 dispose를 호출하지 못한 경우 Finalize는 개체가 관리되지 않는 리소스를 올바르게 닫을 수 있는 마지막 기회입니다.
    (Finalize에서는 Dispose 메서드가 관리되지 않는 리소스를 제외한 모든 항목의 릴리스를 건너뛰는 방식으로 Dispose를 호출하여 이 작업을 수행해야 합니다.또는 개체의 Dispose 메서드가 개체를 인스턴스화한 항목에 의해 적절하게 호출된 경우 개체가 인스턴스화한 모든 IDisposable 개체에 대한 Dispose 호출을 전달하고 관리되지 않는 리소스를 적절하게 해제한 후 개체에서 Finalize를 억제하는 호출로 끝납니다. , 이는 호출자가 개체를 적절하게 처리한 경우 Finalize 사용의 영향이 줄어드는 것을 의미합니다.이 모든 요점은 Keith의 게시물 BTW에 포함되어 있습니다.)

    b.2) 클래스가 인스턴스화된 IDisposable 개체에 Dispose를 본질적으로 전달해야 하기 때문에 IDisposable만 구현하는 경우 클래스에서 Finalize 메서드를 구현하지 마세요.Finalize는 개체를 인스턴스화한 항목에서 Dispose가 모두 호출되지 않았고 아직 릴리스되지 않은 관리되지 않는 리소스가 활용된 경우를 처리하기 위한 것입니다.

간단히 말해서 Keith의 게시물에 대해서는 그가 완전히 정확하며 내 생각에는 그 게시물이 가장 정확하고 완전한 답변입니다.그는 일부 사람들이 '틀렸다'고 생각하거나 반대하는 몇 가지 간단한 진술을 사용할 수 있지만 그의 전체 게시물은 Finalize 사용에 대해 완전히 확장되었으며 그는 절대적으로 정확합니다.그의 게시물에 있는 규칙이나 예비 진술 중 하나에 뛰어들기 전에 그의 게시물을 완전히 읽으십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top