문제

DataSet과 DataTable은 모두 IDisposable을 구현하므로 일반적인 모범 사례에 따라 Dispose() 메서드를 호출해야 합니다.

그러나 지금까지 읽은 내용에 따르면 DataSet 및 DataTable에는 실제로 관리되지 않는 리소스가 없으므로 Dispose()는 실제로 많은 작업을 수행하지 않습니다.

게다가 그냥 사용할 수도 없고 using(DataSet myDataSet...) DataSet에는 DataTable 컬렉션이 있기 때문입니다.

따라서 안전을 위해 myDataSet.Tables를 반복하고 각 DataTable을 삭제한 다음 DataSet을 삭제해야 합니다.

그렇다면 모든 DataSet 및 DataTable에 대해 Dispose()를 호출하는 번거로움을 감수할 가치가 있습니까?

부록:

DataSet을 폐기해야 한다고 생각하는 분들을 위해:일반적으로 폐기 패턴은 다음을 사용하는 것입니다. using 또는 try..finally, Dispose()가 호출되도록 보장하기를 원하기 때문입니다.

그러나 이것은 컬렉션에 비해 정말 빨리 추악해집니다.예를 들어 Dispose() 호출 중 하나에서 예외가 발생한 경우 어떻게 해야 합니까?다음 요소를 계속 처리할 수 있도록 그것을 삼키십니까("나쁜" 것입니까?)?

아니면 myDataSet.Dispose()를 호출하고 myDataSet.Tables에서 DataTable을 삭제하는 것을 잊어버릴 것을 제안하시겠습니까?

도움이 되었습니까?

해결책

다음은 DataSet에 Dispose가 필요하지 않은 이유를 설명하는 몇 가지 토론입니다.

폐기할 것인가, 폐기하지 않을 것인가?:

DataSet의 Dispose 메서드는 상속의 부작용 때문에만 존재합니다. 즉, 실제로 마무리에 유용한 작업을 수행하지 않습니다.

DataTable 및 DataSet 개체에 대해 Dispose를 호출해야 합니까? MVP의 설명이 포함되어 있습니다.

System.Data 네임 스페이스 (ADONET)에는 관리되지 않는 리소스가 포함되어 있지 않습니다.그러므로 특별한 것을 추가하지 않는 한 어떤 사람도 처벌 할 필요가 없습니다.

Dispose 방법과 데이터 세트를 이해하고 계십니까? 권위자 Scott Allen의 의견이 있습니다.

실제로는 이점이 거의 없기 때문에 DataSet을 폐기하는 경우는 거의 없습니다."

그래서 합의된 점은 다음과 같습니다. 현재로서는 DataSet에서 Dispose를 호출할 이유가 없습니다.

다른 팁

업데이트(2009년 12월 1일):

나는 이 답변을 수정하고 원래 답변에 결함이 있음을 인정하고 싶습니다.

원래 분석 하다 마무리 작업이 필요한 개체에 적용해야 하며, 정확하고 심층적인 이해 없이 표면적으로 실천을 받아들여서는 안 된다는 점은 여전히 ​​유효합니다.

그러나 DataSet, DataView, DataTable은 생성자에서 종료를 억제합니다. – 이것이 Dispose()를 호출해도 명시적으로 아무 작업도 수행되지 않는 이유입니다.

아마도 이는 관리되지 않는 리소스가 없기 때문에 발생합니다.그래서 그 사실에도 불구하고 MarshalByValueComponent 관리되지 않는 리소스를 허용하지만 이러한 특정 구현에는 필요하지 않으므로 마무리를 생략할 수 있습니다.

(.NET 작성자가 일반적으로 가장 많은 메모리를 차지하는 유형에 대한 종료를 억제하는 데 주의를 기울인다는 것은 일반적으로 종료 가능한 유형에 대한 이 관행의 중요성을 말해줍니다.)

그럼에도 불구하고 .NET Framework가 시작된 이래로(거의 8년 전) 이러한 세부 사항이 여전히 문서화되어 있지 않다는 점은 꽤 놀라운 일입니다. 즉, 기본적으로 충돌하고 모호한 자료를 선별하여 조각을 모으는 작업은 사용자 자신의 장치에 맡겨져 있다는 것입니다. 때때로 실망스럽기도 하지만 우리가 매일 사용하는 프레임워크에 대한 더 완전한 이해를 제공합니다).

많이 읽은 후에 내 이해는 다음과 같습니다.

객체에 마무리가 필요한 경우 ~할 수 있었다 필요한 것보다 더 오랫동안 메모리를 차지합니다. 그 이유는 다음과 같습니다.a) 소멸자를 정의하는(또는 소멸자를 정의하는 유형에서 상속되는) 모든 유형은 종료 가능한 것으로 간주됩니다.b) 할당 시(생성자가 실행되기 전) 포인터가 마무리 큐에 배치됩니다.c) 종료 가능한 객체에는 일반적으로 다음이 필요합니다. 컬렉션 2개 (표준 1 대신) 재생됩니다.d) 최종화를 억제하는 것은 최종 큐에서 객체를 제거하지 않습니다 (SOS의 FinalizeQueue에 의해보고 된 바와 같이)이 명령은 오해의 소지가 있습니다.종료 대기열에 어떤 개체가 있는지(그 자체로) 아는 것은 도움이 되지 않습니다.마무리 대기열에 있고 여전히 마무리가 필요한 개체가 무엇인지 아는 것이 도움이 될 것입니다. 이에 대한 명령이 있습니까?

종료를 억제하면 종료자를 호출할 필요가 없음(FReachable 대기열을 이동할 필요가 없음)을 런타임에 나타내는 개체 헤더에서 약간 꺼집니다.마무리 대기열에 남아 있습니다(SOS의 !FinalizeQueue에 의해 계속 보고됨).

DataTable, DataSet, DataView 클래스는 모두 관리되지 않는 리소스를 (잠재적으로) 처리할 수 있는 최종화 가능한 개체인 MarshalByValueComponent에 뿌리를 두고 있습니다.

  • DataTable, DataSet, DataView는 관리되지 않는 리소스를 도입하지 않기 때문에 생성자에서 마무리를 억제합니다.
  • 이는 특이한 패턴이지만 호출자는 사용 후 Dispose 호출에 대해 걱정할 필요가 없습니다.
  • 이는 DataTable이 잠재적으로 여러 DataSet에서 공유될 수 있다는 사실 때문에 DataSet이 하위 DataTable을 처리하지 않는 이유일 수 있습니다.
  • 이는 또한 이러한 개체가 SOS의 !FinalizeQueue 아래에 나타남을 의미합니다.
  • 그러나 이러한 개체는 완료할 수 없는 개체와 마찬가지로 단일 컬렉션 후에도 여전히 회수 가능해야 합니다.

4(새 참조):

원래 답변:

이에 대해 오해의 소지가 있고 일반적으로 매우 형편없는 답변이 많이 있습니다. 여기에 도착한 사람은 누구나 소음을 무시하고 아래 참고 자료를 주의 깊게 읽어야 합니다.

의심할 여지없이 폐기하세요. 해야한다 종료 가능한 객체에 대해 호출됩니다.

데이터테이블 ~이다 마무리 가능.

Dispose 호출 상당히 메모리 회수 속도가 빨라집니다.

MarshalByValueComponent 전화 GC.SuppressFinalize(this) Dispose()에서 - 이를 건너뛰는 것은 메모리가 회수되기 전에 수백 개의 Gen0 컬렉션은 아니더라도 수십 개를 기다려야 함을 의미합니다.

결승에 대한 기본적인 이해를 통해 우리는 이미 매우 중요한 것들을 이미 추론 할 수 있습니다.

첫째, 마무리가 필요한 객체는 그렇지 않은 객체보다 더 오래 산다.실제로 그들은 훨씬 더 오래 살 수 있습니다.예를 들어, Gen2에있는 객체를 마무리해야한다고 가정하십시오.최종화가 예정되어 있지만 객체는 여전히 Gen2에 있으므로 다음 Gen2 컬렉션이 발생할 때까지 다시 수집되지 않습니다.실제로는 매우 오랜 시간이 걸릴 수 있으며, 실제로 일이 잘 진행되고 있다면 Gen2 컬렉션은 비용이 많이 들기 때문에 우리는 그것들이 매우 드물게 일어나기를 원하기 때문에 오랜 시간이 걸릴 것입니다.마무리가 필요한 오래된 물체는 공간이 회수되기 전에 수백 개의 Gen0 컬렉션이 아니라면 수십을 기다려야 할 수도 있습니다.

둘째, 마무리가 필요한 물체는 담보 손상을 유발합니다.내부 객체 포인터는 유효성을 유지해야하므로 마무리가 필요한 객체는 메모리에 직접 남아있을뿐만 아니라 객체가 직간접 적으로 말하는 모든 것도 메모리에 남아 있습니다.거대한 물체의 트리가 단일 객체에 의해 정박 된 경우, 방금 논의했던 것처럼 오랫동안 오랫동안 나무 전체가 남아있을 것입니다.따라서 최종화기를 드물게 사용하고 가능한 한 내부 객체 포인터가 거의없는 개체에 배치하는 것이 중요합니다.내가 방금 준 나무 예에서, 마무리가 필요한 자원을 별도의 물체로 옮기고 나무의 루트에있는 그 물체에 대한 참조를 유지함으로써 문제를 쉽게 피할 수 있습니다.그 겸손한 변화로 단 하나의 물체 만 (좋은 작은 물체)가 남아 있고 마무리 비용이 최소화됩니다.

마지막으로, 최종화가 필요한 객체는 Finalizer 스레드에 대한 작업을 만듭니다.최종화 프로세스가 복잡한 프로세스 인 경우, 하나의 최종 분야 스레드는 해당 단계를 수행하는 데 많은 시간을 소비하여 작업의 백 로그를 유발하여 더 많은 물체가 마무리를 기다리는 것을 유발할 수 있습니다.따라서 최종화 업체가 가능한 한 적은 작업을 수행하는 것이 매우 중요합니다.또한 모든 객체 포인터가 최종화 중에 유효성을 유지하지만 해당 포인터가 이미 완료되었으므로 유용하지 않은 객체로 이어질 수 있습니다.포인터가 유효하더라도 최종화 코드에서 객체 포인터를 따르는 것을 피하는 것이 일반적으로 가장 안전합니다.안전하고 짧은 마무리 코드 경로가 가장 좋습니다.

Gen2에서 수백 MB의 참조되지 않은 DataTable을 본 사람의 말을 들어보세요.이것은 매우 중요하며 이 스레드의 답변에서는 완전히 놓쳤습니다.

참고자료:

1 - http://msdn.microsoft.com/en-us/library/ms973837.aspx

2 - http://vineetgupta.spaces.live.com/blog/cns!8DE4BDC896BEE1AD!1104.entry http://www.dotnetfunda.com/articles/article524-net-best-practice-no-2-improve-garbage-collector-performance-using-finalizedispose-pattern.aspx

3 - http://codeidol.com/csharp/net-framework/Inside-the-CLR/Automatic-Memory-Management/

유용한 작업을 수행한다고 가정하고 current 에서 아무 작업도 수행하지 않더라도 Dispose를 호출해야 합니다.NET Framework 화신이므로 향후 버전에서도 그대로 유지되어 비효율적인 리소스 사용으로 이어질 것이라는 보장은 없습니다.

개체에 관리되지 않는 리소스가 없더라도 삭제하면 개체 그래프가 손상되어 GC에 도움이 될 수 있습니다.일반적으로 개체가 IDisposable을 구현하는 경우 Dispose()를 호출해야 합니다.

Dispose()가 실제로 어떤 작업을 수행하는지 여부는 해당 클래스에 따라 다릅니다.DataSet의 경우 Dispose() 구현이 MarshalByValueComponent에서 상속됩니다.컨테이너에서 자신을 제거하고 Disposed 이벤트를 호출합니다.소스 코드는 아래와 같습니다(.NET Reflector로 분해됨).

protected virtual void Dispose(bool disposing)
{
    if (disposing)
    {
        lock (this)
        {
            if ((this.site != null) && (this.site.Container != null))
            {
                this.site.Container.Remove(this);
            }
            if (this.events != null)
            {
                EventHandler handler = (EventHandler) this.events[EventDisposed];
                if (handler != null)
                {
                    handler(this, EventArgs.Empty);
                }
            }
        }
    }
}

DataTable을 직접 만드시나요?DataSet.Tables에서와 같이 모든 개체의 자식을 반복하는 것은 일반적으로 필요하지 않습니다. 모든 자식 멤버를 삭제하는 것이 부모의 작업이기 때문입니다.

일반적으로 규칙은 다음과 같습니다.이를 생성하고 IDisposable을 구현하는 경우 이를 폐기합니다.생성하지 않은 경우 폐기하지 마십시오. 이는 상위 개체의 작업입니다.그러나 각 객체에는 특별한 규칙이 있을 수 있습니다. 문서를 확인하세요.

.net 3.5의 경우 "더 이상 사용하지 않을 때는 폐기하세요"라고 명시되어 있으므로 그렇게 하겠습니다.

개체가 IDisposeable을 구현할 때마다 dispose를 호출합니다.거기에는 이유가 있습니다.

DataSet은 엄청난 메모리를 차지할 수 있습니다.정리 표시는 빨리할수록 좋습니다.

업데이트

이 질문에 답한 지 5년이 지났습니다.나는 여전히 내 대답에 동의합니다.dispose 메서드가 있는 경우 개체 작업이 완료되면 호출되어야 합니다.IDispose 인터페이스가 구현된 이유는 다음과 같습니다.

이 질문의 의도나 맥락이 실제로 가비지 수집이라면 데이터 세트와 데이터 테이블을 명시적으로 null로 설정하거나 using 키워드를 사용하여 범위를 벗어나도록 할 수 있습니다.Dispose는 앞서 Tetraneutron이 말한 것처럼 많은 작업을 수행하지 않습니다.GC는 더 이상 참조되지 않는 데이터세트 개체와 범위를 벗어난 개체를 수집합니다.

나는 정말로 사람들이 답변을 반대 투표하기 전에 실제로 댓글을 쓰도록 투표를 거부하기를 바랍니다.

데이터 세트는 IDisposable을 구현하는 MarshalByValueComponent를 통해 IDisposable을 구현합니다.데이터 세트가 관리되므로 dispose를 호출해도 실질적인 이점은 없습니다.

Clear() 함수를 사용해 보세요.처분하는 데 아주 효과적입니다.

DataTable dt = GetDataSchema();
//populate dt, do whatever...
dt.Clear();

데이터 세트가 MarshalbyValuecomponent 클래스 및 MarshalbyValueComponent를 IDISPosable 인터페이스로 구현하기 때문에 ()를 폐기 할 필요가 없습니다.

먼저 Dispose가 DataSet으로 수행하는 작업을 확인하겠습니다.아마도 redgate의 반사경을 사용하는 것이 도움이 될 것입니다.

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