GC의 메모리 처리 방식과 현재 발생되는 이슈가 뒤섞여 원인을 찾기 어려워지는 것 같아 댓글 달아요~
(오래된 기억이라 틀린 내용이 있으시면 말씀해주세요~)
닷넷의 메모리는 Managed, UnManaged로 나뉩니다.
- Managed는 개발 할때 흔히 선언하는 클래스나, 멤버 변수들을 포함합니다. 심지어 이전에 공유 드렸던 FileStream의 멤버 변수인 SafeFileHandle도 Managed 입니다.
- UnManaged는 네트워크 소켓 핸들, 파일 핸들, COM 객체, 뮤텍스 등 닷넷 런타임 밖에 있는 자원들이 UnManaged 메모리 영역입니다.
앞서 말씀드린 Managed 영역의 SafeFileHandle에 연결된 실제 파일 핸들을 예로 들 수 있습니다.
닷넷 런타임은 적절한 시기에 GC(가비지 컬렉터)를 실행하고, GC는 Managed 영역의 인스턴스들을 대상으로 Object Graph를 그려 사용하고 있는 인스턴스와 사용하고 있지 않은 인스턴스를 걸러내고, 사용하지 않는 인스턴스의 메모리를 해제한 후 최적화합니다.(해제된 메모리로 조각난 메모리 영역을 재정렬 합니다.)
그래서 FileStream의 Dispose 함수에서 _canRead, _canWrite, _canSeek과 같은 Managed 영역 변수들은 초기화할 뿐 별다른 조치를 하지 않는 것은 GC가 나중에 처리해주기 때문으로 이해해주시면 될 것 같습니다.
공유해주신 이팩티브 c#도 앞서 말씀드린 맥락으로 이해해보자면, SqlConnection 인스턴스의 멤버변수들은 Managed 메모리 영역이므로 GC에 의해 메모리가 해제 됩니다.
단, 데이터베이스 연결 핸들은 UnManaged 영역이므로 Dispose 함수 내부에서 처리합니다.
만약 Dispose 함수를 부르지 않고 지나쳤는데 사용하지 않는 인스턴스면 어떻게 될까요?
c#은 소멸자를 통해 UnManaged 영역의 메모리 해제를 할수 있도록 지원합니다.
이슈가 어떤 이유로 발생되었는지 정확히 알수는 없지만, 이전에 멀티 스레드 환경에서 압축, 파일 이동과 같은 처리를 하신다고 했었는데 단일 스레드에서 이슈가 없는지 그리고 각 Task(압축, 이동)를 나누어서 할 때 이슈가 없는 지 테스트 해 보시는게 어떨까 싶네요.