질문이 하나 있군요.
안녕하세요 WPF 에서 Window객체가 가비지 콜렉션에 의해 수집되지 않는거 같아서 문의드립니다. ; http://www.sysnet.pe.kr/3/0/4896
실제로 WPF에서 다음과 같은 간단한 소스 코드로,
using System.Linq; using System.Windows; namespace WpfApp1 { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { foreach (int n in Enumerable.Range(1, 100000)) { Window win = new Window(); } } } }
버튼 클릭 몇 번을 하면 OOM 예외가 발생하도록 만들 수 있습니다. 얼핏 보면 new Window만 했으니 GC 대상이 되어야 하지만 그렇지 않은 현상을 보이는 것입니다.
이런 경우 생각할 여지가 별로 없으니 다행입니다. 수행된 코드는 어차피 생성자 뿐이 없으니 그 안에서 아마도 다른 루트 객체에 자신의 참조를 추가했을 것입니다. 확인을 위해 .NET Reflector 등으로 소스 코드를 확인하면 답이 나오겠지요.
실제로 PresentationFramework 어셈블리의 System.Windows.Window 타입의 생성자를 찾아보면,
[SecurityCritical]
public Window()
{
this._ownerHandle = IntPtr.Zero;
this._updateHwndSize = true;
this._updateHwndLocation = true;
this._trackMaxWidthDeviceUnits = double.PositiveInfinity;
this._trackMaxHeightDeviceUnits = double.PositiveInfinity;
this._windowMaxWidthDeviceUnits = double.PositiveInfinity;
this._windowMaxHeightDeviceUnits = double.PositiveInfinity;
this._actualTop = double.NaN;
this._actualLeft = double.NaN;
this._dialogOwnerHandle = IntPtr.Zero;
this._prePanningLocation = new Point(double.NaN, double.NaN);
SecurityHelper.DemandUnmanagedCode();
this._inTrustedSubWindow = false;
this.Initialize();
}
다른 코드는 상관이 없으니 이젠 Initialize를 의심해 볼 수 있습니다.
private void Initialize() { base.BypassLayoutPolicies = true; if (this.IsInsideApp) { if (Application.Current.Dispatcher.Thread == Dispatcher.CurrentDispatcher.Thread) { this.App.WindowsInternal.Add(this); if (this.App.MainWindow == null) { this.App.MainWindow = this; } } else { this.App.NonAppWindowsInternal.Add(this); } } }
아하... 여기 있군요. WindowsInternal이든 NonAppWindowsInternal이든 자신을 추가하고 있습니다. 이렇게 this.App 객체가 참조를 잡아 두고 있으니 GC 해제가 안된 것입니다.
만약 참조 해제를 하고 싶다면 명시적으로 Close 메서드를 호출해 주면 됩니다.
foreach (int n in Enumerable.Range(1, 100000))
{
Window win = new Window();
win.Close();
}
그런데, 조금 궁금한 부분이 있군요. 왜 WPF 개발팀은 Window 객체에 명시적으로 자원 해제를 위한 IDisposable 인터페이스를 구현하지 않았을까요?