Dispose () DataSet 및 DataTable을해야합니까?


197

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

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

또한 using(DataSet myDataSet...)DataSet에는 DataTable 컬렉션이 있으므로 사용할 수 없습니다 .

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

따라서 모든 DataSet 및 DataTable에서 Dispose ()를 호출하는 것이 번거 롭습니까?

추가:

당신의 그 누구 데이터 집합을 배치해야한다고 생각 : 일반적으로, 폐기에 대한 패턴을 사용하는 것 using또는try..finally 당신이 폐기 ()가 호출 될 것을 보장을 원하기 때문에.

그러나 이것은 컬렉션에 대해 추악하게 빠릅니다. 예를 들어 Dispose () 호출 중 하나에서 예외가 발생하면 어떻게해야합니까? 다음 요소를 계속 처리 할 수 ​​있도록 삼키는가 ( "나쁜"것)?

아니면 그냥 myDataSet.Dispose ()를 호출하고 myDataSet.Tables에 DataTable을 배치하는 것을 잊어 버릴 것을 제안합니까?


9
Dispose는 예외를 발생시키지 않습니다. 제대로 작성되지 않은 경우 다음을 시도해보십시오. {some.Dispose (); } catch {}이면 충분합니다. - blogs.msdn.com/b/clyon/archive/2004/09/23/233464.aspx
LukeSw

3
많은 DataSet 객체를 사용하는 내 앱 중 하나에서 명백한 메모리 누수가 발견되었습니다. .Dispose ()를 호출하지 않았거나 해당 객체에 "using"블록을 사용하지 않았습니다. 그래서 코드를 살펴보고 DataSet 또는 DataTable을 생성하는 모든 위치에 "using"블록을 추가했으며 이제 메모리가 해제되었습니다. 실제로 .Dispose ()가 DataSet 및 DataTable에 필요하다는 확실한 표시 인 것 같습니다.
dizzy.stackoverflow 1

답변:


147

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

처분하거나 처분하지 않겠습니까? :

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

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

system.data 네임 스페이스 (ADONET)에는 관리되지 않는 리소스가 없습니다. 따라서 자신에게 특별한 것을 추가하지 않은 한 어떤 것도 폐기 할 필요가 없습니다.

Dispose 메서드 및 데이터 집합을 이해하고 있습니까? 권위자 Scott Allen의 의견이 있습니다.

실제로는 거의 혜택을 제공하지 않으므로 DataSet을 거의 처리하지 않습니다. "

따라서 현재 DataSet에서 Dispose를 호출해야 할 합당한 이유가 없습니다.


7
제공된 링크는 DataTable이 Finalizable 객체 유형이라는 점을 완전히 놓쳤습니다. 아래의 Nariman의 답변을 참조하십시오.
허먼

흥미로운 답변이지만 SqlConnection, SqlCommand 및 SqlDataAdapter는 Dispose를 명시 적으로 호출해야합니까?
Willy

@ 윌리 많은 사람들이 IDisposables에 using 문을 사용한다고 생각합니다. (SqlConnection cn = new SqlConnection (connectionString)) 사용하기 {((SqlCommand cm = new SqlCommand (commandString, cn)) 사용하기) {cn.Open (); cm.ExecuteNonQuery (); }}
DOK

1
@ 윌리 네, 관리되지 않는 리소스를 사용하기 때문에 절대적으로 처리해야합니다. using블록을 사용하여 명시 적으로 또는 암시 적으로 호출하는지 여부 는 귀하에게 달려 있습니다.
D Stanley

129

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

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

원래 분석 마무리가 필요한 물체에 적용됩니다. 정확하고 깊이있는 이해가 없으면 표면에서 관행을 받아들이지 않아야하는 시점이 있습니다.

그러나 DataSets, DataViews, DataTables 는 생성자에서 마무리를 억제합니다. 따라서 Dispose ()를 호출하면 명시 적으로 아무 작업도 수행되지 않습니다.

아마도 이것은 관리되지 않는 리소스가 없기 때문에 발생합니다. 따라서 MarshalByValueComponent 가 관리되지 않는 리소스를 허용 한다는 사실에도 불구하고 이러한 특정 구현에는 필요가 없으므로 마무리 작업을 포기할 수 없습니다.

.NET 작성자는 일반적으로 메모리를 가장 많이 차지하는 형식에 대한 마무리를 억제하기 위해주의를 기울여야합니다.이 형식은 일반적으로이 형식이 중요합니다.

그럼에도 불구하고 (약 8 년 전) .NET Framework를 시작한 이후로 이러한 세부 사항은 여전히 ​​문서화되지 않았다는 점이 놀랍습니다. 때때로 실망 스럽지만 우리가 일상적으로 사용하는 프레임 워크에 대한보다 완전한 이해를 제공합니다).

많은 독서 후, 여기 내 이해가 있습니다 :

객체가 마무리가 필요한 경우, 필요한 것보다 더 오래 메모리를 차지할 있습니다. 이유는 다음과 같습니다. a) 소멸자를 정의하는 유형 (또는 소멸자를 정의하는 유형에서 상속 된)은 최종적인 것으로 간주됩니다. b) 할당시 (생성자가 실행되기 전에) 포인터가 종료 큐에 배치됩니다. c) 종료 가능한 객체는 일반적으로 종료 종료는 객체의 헤더에서 비트를 해제하여 런타임에 종료자가 호출 될 필요가 없음을 나타냅니다 (FReachable 대기열을 이동할 필요는 없음). 종료 큐에 남아 있으며 SOS의! FinalizeQueue에서 계속보고합니다. 표준 1 대신 2 개의 수집 물 을 회수해야한다. d) 종료를 억제해도 종료 큐에서 오브젝트가 제거되지 않습니다 (SOS의! FinalizeQueue에서보고 됨)이 명령은 잘못된 것입니다. 종료 큐에 어떤 객체가 있는지 아는 것은 도움이되지 않습니다. 마무리 대기열에 어떤 객체가 있고 여전히 마무리가 필요한지 아는 것이 도움이 될 것입니다 (이에 대한 명령이 있습니까).

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

  • DataTable, DataSet, DataView는 관리되지 않는 리소스를 도입하지 않기 때문에 생성자의 마무리를 억제합니다.
  • 이것은 비정상적인 패턴이지만 사용 후 발신자가 Dispose 호출에 대해 걱정할 필요가 없습니다.
  • 이는 DataTable이 다른 DataSet간에 공유 될 수 있다는 사실 때문에 DataSet이 하위 DataTable을 처리하지 않는 이유 일 수 있습니다.
  • 이는 또한 이러한 객체가 SOS의! FinalizeQueue 아래에 표시됨을 의미합니다.
  • 그러나 이러한 개체는 최종 수집 할 수없는 대응 물과 같이 단일 컬렉션 후에도 계속 재생 가능해야합니다.

4 (신규 참조) :

원래 답변 :

여기에 착륙 한 사람은 소음을 무시하고 아래의 참고 사항을주의 깊게 읽어야합니다.

의심 할 여지없이, Dispose Finalizable 객체에 대해 호출 해야 합니다.

데이터 테이블 최종화 가능합니다.

Dispose를 호출 하면 메모리 재생 속도가 크게 빨라집니다.

MarshalByValueComponent 는 Dispose ( ) 에서 GC.SuppressFinalize (this) 를 호출합니다. 이를 건너 뛰는 것은 메모리가 재생되기 전에 수백 개의 Gen0 컬렉션이 아닌 경우 수십을 기다려야한다는 것을 의미합니다.

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

첫째, 마무리가 필요한 객체는 그렇지 않은 객체보다 오래 산다. 사실, 그들은 훨씬 더 오래 살 수 있습니다. 예를 들어, gen2에있는 오브젝트를 마무리해야한다고 가정하십시오. 종료는 예약되지만 개체는 여전히 gen2에 있으므로 다음 gen2 수집이 발생할 때까지 다시 수집되지 않습니다. gen2 컬렉션은 비용이 많이 들기 때문에 매우 드물게 발생하기를 원하기 때문에 실제로는 오랜 시간이 걸릴 수 있습니다. 공간을 확보하기 전에 수백 개의 gen0 컬렉션이 아닌 경우 마무리가 필요한 오래된 개체는 수십을 기다려야 할 수도 있습니다.

둘째, 마무리가 필요한 물체는 담보 손상을 일으 킵니다. 내부 객체 포인터는 유효한 상태를 유지해야하므로, 최종화가 필요한 객체는 메모리에 남아있을뿐만 아니라 객체가 참조하는 모든 객체가 직간접 적으로 메모리에도 남아 있습니다. 거대한 개체 트리가 마무리가 필요한 단일 개체에 의해 고정 된 경우 방금 논의한 것처럼 전체 트리가 오래 지속될 수 있습니다. 따라서 파이널 라이저를 조금만 사용하고 가능한 한 적은 내부 객체 포인터가있는 객체에 배치하는 것이 중요합니다. 방금 제공 한 트리 예제에서 마무리가 필요한 리소스를 별도의 객체로 이동하고 트리의 루트에서 해당 객체에 대한 참조를 유지하면 문제를 쉽게 피할 수 있습니다.

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

Gen2에서 100MB의 참조되지 않은 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/


좋은 지적. 많은 DataTable이있는 DataSet이있을 때 일반적으로 코드를 어떻게 구성합니까? 문장을 사용하여 톤이 많이 있습니까? 한 번에 한 번에 모두 정리할 수 있습니까?
mbeckish

14
"그러나 DataSets, DataViews, DataTables는 생성자의 마무리를 억제한다는 것이 밝혀졌습니다. 이것이 Dipose ()를 호출하면 명시 적으로 아무 것도 수행되지 않는 이유입니다." 두 가지 개념은 크게 관련이 없습니다. 종료를 억제하는 것은 여전히 ​​Dispose ()에서 무언가를 할 수 있습니다. 우리가 그것을 반대하면 실제로, 실제로 더 의미 : 폐기 ()는 아무것도하지 않는 이유는 합니다 (finaliser 전화로는 GC를 귀찮게하지 않으려는 아무 상관이 없을 것입니다 있기 때문에, 생성자에서 예를 마무리를 억제 일반적으로 dispose라고합니다.
Marc Gravell

감사. 이 토론이 님에게도 적용됩니까 TableAdapter?
Bondolin


24

유용한 것이 있다고 가정하고 current에 아무 것도 없어도 Dispose를 호출해야합니다. NET Framework의 구현에서는 향후 버전에서 이러한 방식을 유지하여 비효율적 인 리소스 사용을 보장하지는 않습니다.


향후 IDisposable을 구현할 것이라는 보장도 없습니다. 사용하는 것처럼 간단하다면 (...) 동의하지만 DataSet의 경우 아무것도 번거롭지 않습니다.
mbeckish

28
항상 IDisposable을 구현한다고 가정하는 것이 상당히 안전합니다. 인터페이스의 추가 또는 제거는 주요 변경 사항이지만 Dispose 구현은 변경되지 않습니다.
Greg Dean

5
또한 다른 공급자는 실제로 IDisposable로 무언가를 수행하는 구현을 가질 수 있습니다.
매트 스프 래들리

말할 것도 DataTable없고 봉인 된 것도 아닙니다-당신이 할 때 큰 일 new DataTable이 아니지만 DataTable인수 또는 메소드 호출의 결과로 취할 때 매우 중요 합니다.
Luaan

17

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

Dispose ()가 실제로 무언가를 수행하는지 여부는 주어진 클래스에 따라 다릅니다. DataSet의 경우 Dispose () 구현은 MarshalByValueComponent에서 상속됩니다. 컨테이너에서 자신을 제거하고 Disposed 이벤트를 호출합니다. 소스 코드는 다음과 같습니다 (.NET 리플렉터로 분해됨).

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);
                }
            }
        }
    }
}

1
과연. 최근에는 Dispose없이 많은 수의 DataTable이 매우 큰 루프로 작성된 일부 코드가 나타났습니다. 이로 인해 컴퓨터에서 모든 메모리가 소비되고 메모리 부족으로 프로세스가 중단됩니다. 개발자에게 DataTable에 대해 dispose를 호출하도록 요청한 후에 문제가 해결되었습니다.
RichardOD 2016 년

7

DataTable을 직접 작성합니까? DataSet.Tables에서와 같이 모든 Object의 자식을 반복하는 것은 일반적으로 필요하지 않기 때문에 부모의 모든 자식 멤버를 처리하는 것이 부모의 작업이기 때문입니다.

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

.net 3.5의 경우 명시 적으로 "더 이상 사용하지 않을 때는 폐기하십시오"라고 표시되어 있습니다.


4
내가 이해 한 바에 따르면 일반적인 합의는 개체가 자체 관리되지 않는 리소스를 처리해야한다는 것입니다. 그러나 IDisposable 객체의 컬렉션은 일반적으로 컬렉션 외부에있는 요소에 대한 다른 참조가있을 수 있기 때문에 각 요소를 처리하기 위해 해당 요소를 반복하지 않습니다. stackoverflow.com/questions/496722/…
mbeckish

1
사실, 컬렉션은 항상 내가 "무엇을"하지 "않기 때문에 항상 특별하다고 생각하는 것입니다. 컨테이너 일뿐입니다.
Michael Stum

7

객체가 IDisposeable을 구현할 때마다 dispose를 호출합니다. 이유가 있습니다.

데이터 세트는 거대한 메모리 호그 일 수 있습니다. 정리 표시가 빠를수록 빠를수록 좋습니다.

최신 정보

이 질문에 답한 지 5 년이 지났습니다. 나는 여전히 내 대답에 동의합니다. dispose 메서드가 있으면 개체를 다룰 때 호출해야합니다. IDispose 인터페이스가 이유로 구현되었습니다.


5
dispose를 호출해도 메모리 재생 속도가 빨라지지 않으므로 일반적으로 잘못된 계획 인 가비지 수집기를 수동으로 시작해야합니다.
Tetraneutron

2
Dispose가 많은 참조를 null로 설정하면 개체가 수집 대상이되어 건너 뛸 수 있습니다.
Greg Dean

1
Dispose의 요점은 관리 대상 개체의 메모리를 지우는 것이 아니라 가비지 수집기의 작업입니다. 요점은 관리되지 않는 개체를 정리하는 것입니다. DataSet에는 관리되지 않는 참조가 없으므로 이론적으로이를 참조 할 필요가 없다는 증거가 있습니다. 즉, Dispose를 호출하기 위해 나가야 할 상황에 처한 적이 없었습니다. 어쨌든 전화 할 것입니다.
cbp

4
IDisposable 의 주요 용도는 관리되지 않는 리소스를 해제하는 것입니다. 종종 배치 된 인스턴스에 적합한 방식으로 상태를 수정하기도합니다. (즉, 속성은 false, 참조는 null 등으로 설정 됨)
Greg Dean

3
객체에 dispose 메소드가 있으면 관리되지 않는 객체를 정리하기위한 것인지 여부에 관계없이 이유가 있습니다.
Chuck Conway

4

이 질문의 의도 또는 컨텍스트가 실제로 가비지 콜렉션 인 경우 데이터 세트 및 데이터 테이블을 명시 적으로 null로 설정하거나 using 키워드를 사용하여 범위를 벗어날 수 있습니다. Tetraneutron이 이전에 말한 것처럼 처분은별로하지 않습니다. GC는 더 이상 참조되지 않는 데이터 세트 객체와 범위를 벗어난 데이터 세트 객체를 수집합니다.

나는 정말로 투표를 거절 한 사람들이 답을 내리기 전에 실제로 의견을 쓰길 바랍니다.


+ 1 일부 사람들은 다른 사람들이 다른 관점을 고려하는 것을 원하지 않습니다.
DOK

2
다운 투표는 사람들이 다른 관점을 고려하는 것을 허용하지 않습니다.
Greg Dean

1

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


6
나중에 무엇을할지 누가 알겠는가?
Greg Dean

미래에 어떤 코드도 코드를 수행하지 않을 것이라고 추측하는 이러한 태도는 모든 관련자들에 대한 가정의 고통입니다.
MicroservicesOnDDD

0

Clear () 함수를 사용하십시오. 그것은 처분에 나에게 잘 작동합니다.

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

0

DataSet이 MarshalByValueComponent 클래스를 상속하고 MarshalByValueComponent가 IDisposable 인터페이스를 구현하므로 Dispose () 필요 없음

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