none
ListBox相关的内存泄露 RRS feed

  • 问题

  • 我创建了一个用户控件GroupControl,有AddGroup(object header, object[] items)方法。这个方法就是创建一个GroupBox,设置Header和GroupBox里面的ListBox.ItemsSource。

    <ContentControl x:Class="Gqqnbig.TranscendentKill.GroupControl"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300">
        <ItemsControl Name="selectionGroupPanel" x:FieldModifier="private" HorizontalAlignment="Left" VerticalAlignment="Top"/>
    </ContentControl>




        public partial class GroupControl
        {
            public GroupControl()
            {
                InitializeComponent();
            }
    
            public event SelectionChangedEventHandler SelectionChanged;
    
            public void AddGroup(object header, object[] items)
            {
                GroupBox groupBox = new GroupBox();
                groupBox.Header = header;
                ListBox listBox = new ListBox();
                listBox.ItemsSource = items;
                listBox.SelectionChanged += listBox_SelectionChanged;
                groupBox.Content = listBox;
    
                selectionGroupPanel.Items.Add(groupBox);
            }
    
            void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                if (SelectionChanged != null)
                    SelectionChanged(this, e);
            }
        }


    然后主窗口使用这个GroupControl,在窗口加载的时候往GroupControl里填数据,当用户选择GroupControl里任意一项的时候,卸载这个GroupControl。

    代码稍显繁琐,因为这是从我的真实项目中抽取出来用来演示问题的。

        internal partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
    
            private void Window_Loaded_1(object sender, RoutedEventArgs e)
            {
                Tuple<string, object[]>[] cps = new Tuple<string, object[]>[2];
                cps[0] = new Tuple<string, object[]>("时间", new[] { (object)DateTime.Now.ToShortTimeString() });
                cps[1] = new Tuple<string, object[]>("日期", new[] { (object)DateTime.Now.ToShortDateString() });
    
    
                GroupControl win = new GroupControl();
    
                for (int i = 0; i < cps.Length; i++)
                {
                    ContentPresenter[] items = new ContentPresenter[cps[i].Item2.Length];
    
                    for (int j = 0; j < cps[i].Item2.Length; j++)
                        items[j] = new ContentPresenter { Content = cps[i].Item2[j] };
    
                    win.AddGroup(cps[i].Item1, items);
                }
    
                win.SelectionChanged += win_SelectionChanged;
                Content = win;
            }
    
            void win_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                GroupControl win = (GroupControl)this.Content;
                win.SelectionChanged -= win_SelectionChanged;
    
                Content = null;
    
    
                GC.Collect();
            }
        }
    <Window x:Class="Gqqnbig.TranscendentKill.UI.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Width="800" x:ClassModifier="internal" Loaded="Window_Loaded_1">
    
    </Window>

    当卸载了GroupControl之后,尽管也调用了GC,我用.NET Memory Profiler查看,发现它还是存在。


    上图表示GroupBox._contextStorage保存了我的GroupControl;ListBox._parent保存了前面的GroupBox; ItemsPresenter保存了前面的ListBox;以此类推。因为有对GroupControl的引用链存在,所以它无法被垃圾回收。

    从前几行来看,都是GroupControl和ListBox、ListBoxItem等的相互引用,这个不成问题。我觉得可能是ListCollectionView跟外部做了什么交互,被引用上了,导致一连串都不能被回收。

    能否请各位大侠解释一下这种现象,并请问如何切断这个引用链,让GroupControl能被回收呢?







    2013年2月3日 15:27

答案