Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일

(시리즈 글이 7개 있습니다.)
디버깅 기술: 68. windbg 분석 사례 - 메모리 부족
; https://www.sysnet.pe.kr/2/0/1837

디버깅 기술: 123. windbg - 닷넷 응용 프로그램의 메모리 누수 분석
; https://www.sysnet.pe.kr/2/0/11808

.NET Framework: 807. ClrMD를 이용해 메모리 덤프 파일로부터 특정 인스턴스를 참조하고 있는 소유자 확인
; https://www.sysnet.pe.kr/2/0/11809

.NET Framework: 944. C# - 인스턴스가 살아 있어 메모리 누수가 발생하고 있는지 확인하는 방법
; https://www.sysnet.pe.kr/2/0/12341

디버깅 기술: 171. windbg - 인스턴스가 살아 있어 메모리 누수가 발생하고 있는지 확인하는 방법
; https://www.sysnet.pe.kr/2/0/12342

.NET Framework: 945. C# - 닷넷 응용 프로그램에서 메모리 누수가 발생할 수 있는 패턴
; https://www.sysnet.pe.kr/2/0/12343

VS.NET IDE: 167. Visual Studio 디버깅 중 GC Heap 상태를 보여주는 "Show Diagnostic Tools" 메뉴 사용법
; https://www.sysnet.pe.kr/2/0/12699




C# - 인스턴스가 살아 있어 메모리 누수가 발생하고 있는지 확인하는 방법

아래와 같은 상황에서,

WPF - WindowsFormsHost를 담은 윈도우 생성 시 메모리 누수
; https://www.sysnet.pe.kr/2/0/12340

메모리 누수의 원인이... 의심이 가는 "그 인스턴스"가 살아 있어 발생하는 것인지 어떻게 확인할 수 있을까요? 그런 용도로 존재하는 것은 아니지만, WeakReference를 사용하면 그 목적을 이룰 수 있습니다.

예를 들어 위의 글에서 다룬 소스 코드의 MainWindow 측에 WeakReference를 이용해 약간의 코드를 더 추가해 보겠습니다.

using System;
using System.Collections.Generic;
using System.Windows;

namespace WpfApp5
{
    public partial class MainWindow : Window
    {
        System.Windows.Threading.DispatcherTimer _dispatcherTimer;
        Queue<WeakReference> _list = new Queue<WeakReference>();

        public MainWindow()
        {
            InitializeComponent();

            _dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
            _dispatcherTimer.Tick += _dispatcherTimer_Tick;
            _dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
            _dispatcherTimer.Start();
        }

        private void _dispatcherTimer_Tick(object sender, EventArgs e)
        {
            Queue<WeakReference> copyList = new Queue<WeakReference>();

            while (_list.Count > 0)
            {
                WeakReference wr = _list.Dequeue();
                if (wr.Target != null)
                {
                    copyList.Enqueue(wr);
                }
            }

            _list = copyList;
            System.Diagnostics.Trace.WriteLine(_list.Count);
            
            GC.Collect(2, GCCollectionMode.Forced);
        }

        protected override void OnInitialized(EventArgs e)
        {
            base.OnInitialized(e);
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var window = new Window1();
            window.Show();

            WeakReference wr = new WeakReference(window);
            _list.Enqueue(wr);
        }
    }
}

결과 비교를 위해 우선 메모리 누수가 발생하는 걸 확인해 봐야겠죠? 이를 위해 "Window1"의 OnClosed에서 WindowsFormsHost.Dispose 호출을 주석 처리한 후,

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
    }

    protected override void OnClosed(EventArgs e)
    {
        // clsInstance.Dispose();
        base.OnClosed(e);
    }
}

Visual Studio에서 F5(Start Debugging) 키를 눌러 실행, "Button"을 누를 때마다 Output 창에 나오는 WeakReference.Target 속성 값이 살아 있는 수가 출력되고, 바로 그것이 쌓이면 메모리 누수가 되는 것입니다.

반면, 해당 주석을 다시 풀고 실행해 보면, 이제 GC.Collect로 인해 WindowsFormsHost 개체들이 정상적으로 GC 수집이 되므로 Button을 누를 때마다 Output 창에는 잠시 수가 늘었다가 0으로 내려가는 것을 볼 수 있습니다. 간단하죠?! ^^

(첨부 파일은 이 글의 예제 코드를 포함합니다.)




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 9/23/2020]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 166  167  168  169  170  171  172  173  [174]  175  176  177  178  179  180  ...
NoWriterDateCnt.TitleFile(s)
695정성태4/10/200926226    답변글 .NET Framework: 126.3. CAG - 간단한 유형의 모듈 제작파일 다운로드1
703정성태4/18/200925137        답변글 .NET Framework: 126.6. CAG - Tabbed MDI Shell 적용파일 다운로드1
697정성태4/13/200929432    답변글 .NET Framework: 126.4. CAG - Unity 컨테이너 사용 [1]파일 다운로드1
698정성태4/15/200928655    답변글 .NET Framework: 126.5. CAG에 MVVM 패턴 적용 (1) [2]파일 다운로드1
686정성태4/4/200950284웹: 11. IE 8 - TabProcGrowth 레지스트리 키 [2]
685정성태4/3/200950953개발 환경 구성: 38. Hyper-V 사용 후기 [5]
684정성태4/2/200925589오류 유형: 74. IE 8 설치 이후, VS.NET 위저드 화면 동작 오류
683정성태3/28/200932356디버깅 기술: 26. 보호 모드로 응용 프로그램 디버깅하는 방법 - 두 번째 이야기 [3]
682정성태3/27/200929399디버깅 기술: 25. 보호 모드로 응용 프로그램 디버깅하는 방법 [2]
681정성태3/23/200926469오류 유형: 73. SQL Server 2008 Express 설치 오류
680정성태3/21/200926440.NET Framework: 125. WPF - RadioButton에 대한 데이터바인딩(2) [1]파일 다운로드1
679정성태3/15/200921363오류 유형: 72. IE 8 멈춤 현상 - 두 번째 이야기
678정성태3/15/200926665개발 환경 구성: 37. Hyper-V에서 Vista의 Virtual Machine Bus 장치 인식 문제
677정성태3/15/200927089개발 환경 구성: 36. MSI P45 Neo3-FR V2 - RAID 1 구성
997정성태2/26/201122551    답변글 개발 환경 구성: 36.1. 개발 환경 구성: 34 - 1. RAID 1 구성 이후...
676정성태3/15/200923820오류 유형: 71. IE 8 RC1 - 멈춤 현상
675정성태3/14/200926635오류 유형: 70. Virtual Machine Additions 제거
673정성태3/11/200925205웹: 10. 금일 진행되었던 마이크로소프트 IE 8 행사의 ActiveX 세션 PPT [6]파일 다운로드1
672정성태3/1/200938350Windows: 43. Loopback network adapter 설치하기 [2]
670정성태2/22/200931696.NET Framework: 124. IIS 7에서 SVC 호스팅 [1]
669정성태2/21/200925912오류 유형: 69. The SQL Server Network Interface library could not register the Service Principal Name (SPN) for the SQL Server service.
668정성태2/21/200931051개발 환경 구성: 35. SQL Express 버전과 User Instance 옵션
667정성태2/14/200942905웹: 9. IE 7. IWebBrowser2 인터페이스 메서드의 Navigate / Navigate2 차이점 [3]파일 다운로드1
666정성태2/12/200929116웹: 8. IE 8: 프로세스와 윈도우의 관계 - LCIE [1]파일 다운로드1
665정성태2/7/200925871웹: 7. Internet Explorer 8 - XHR, XDR, XST, XSRF [1]
664정성태2/5/200921866Windows: 42. Concurrency Runtime
... 166  167  168  169  170  171  172  173  [174]  175  176  177  178  179  180  ...