본문 바로가기

Dev::DotNet/WPF

DependencyPropertyDescriptor 사용시 주의사항 - Memory leak

WPF 의 DependencyProperty 의 값 변경에 대해서 통지를 받고 싶으면 


DependencyPropertyDescriptor 를 통해서 쉽게 할 수 있다.



WPF 에서 사용되는 컨트롤은 DependencyObject 를 상속받았고 많은 속성을 DependencyProperty 로 


정의되어 있다.


그렇기 때문에 Property 의 값이 변경되었을 때, 통지를 받을 수 있는 DependencyPropertyDescriptor 는 


매우 유용하게 사용할 수 있다.


컨트롤에서 제공해주는 이벤트뿐만 아니라 단순 Property 의 상태변화까지도 통지를 받아서 


처리할 수 있으니까 말이다.


DependencyPropertyDescriptor 를 획득하고  AddValueChanged 를 통해서 대상 객체와 Handler 를 지정하면 


쉽게 해당 객체의 DependencyProperty의 값 변경을 통지받을 수 있다.


당연히 RemoveValueChanged 를 통해서 해제가 가능하다.



문제는 해제에 있다.


만약 어떠한 이유에서든 AddValueChanged를 통해서 변경 통지를 구독을 하고 


RemoveValueChanged 를 통해서  해제를 하지 않는다면 등록된 객체는 프로세스가 끝날 때까지 GC 에 의해서 


해제가 되지 않는다. (당연히 GC 의 해제 조건에 만족하지 않는다)


대부분의 개발자들이 등록 후, 해제를 할 것이다.



WPF 의 개발 특성상, 많은 컨트롤이 공통된 Style 지정이 되어 있을 것이고, 많은 기능에 대해서 


Attached Behavior 로 만들어서 XAML 에 사용되었을 것이다.



Attached Behavior 는 기본적으로 XAML 에서 사용을 하기 때문에 첨부된 Behavior 기능에 대해서 


Behind Code 부분에서 알아내기 힘들고 해제 작업을 진행하기도 힘들다.



해당 컨트롤이 참조가 끈겨서 GC 에 의해서 소멸할 때, 


그에 속한 Behavior 도 GC 에 의해서 같이 소멸되기를 기다려야 한다.



하지만 이런 Behavior 안에 DependencyPropertyDescriptor 를 통해서 통지를 등록하였다면?


해당 타켓 컨트롤이 소멸되어야 그에 속한 Behavior 도 소멸하는데 해당 컨트롤 자체가 해제되지 않는다.



이것은 문제가 심각하다.


해당 컨트롤이 Main Window 안에 있고 Main Window 소멸할 때, 같이 소멸되는 것이라면 상관없다.


Main Window 의 종료는 프로그램도 같이 종료되니까 말이다.


하지만 특정 Window 를 Show 를 하고 닫았다면 해당 Window 자체가 GC 에 소멸되지 않는다.


WPF는 화려한? UI 를 보여주는 만큼 기본적으로 컨트롤들은 상당히 많은 양의 메모리를 사용한다.


해당 Window 가 반복적으로 자주 생성하여 보이고 닫히는 작업이 반복되게 된다면 


상당량의 Memory 차곡차곡 싸이는 것을 볼 수 있을 것이다.



GC 는 만능이 아니며 개발자는 GC 가 열심히 일을 할 수 있도록 조건을 충족시켜줘야 한다.