업데이트 (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/