Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF memory leak

I have a simple wpf application. In main window i have stack panel and 2 buttons. First button adds 100 my user controls (without any data bindings, events, bitmaps), and second removes all of them from panel and calls GC.Collect(). And there are some problems: 1. After i clicked "remove" button first time not all my memory releases, and I must click it few times to release more memory. 2. After 5 - 10 min memory releases but few megabytes dont.

for example after my app starts it takes ~22mb when i adding 500 controls - ~60mb after i clicked "remove" button first time - ~55mb (I wait some time, memory not deallocated) i click few times and memory fell down to 25mb, I dont understand this, I am new in WPF, and maybe i miss something I want to release memory immediately.

<Window x:Class="WpfApplication10.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="385" Width="553">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="25" />
        <RowDefinition Height="240*" />
        <RowDefinition Height="25" />
    </Grid.RowDefinitions>
    <Grid 
            Name="border1" 
            Grid.Row="1"
            HorizontalAlignment="Stretch"
            VerticalAlignment="Stretch" >
        <ScrollViewer VerticalAlignment="Stretch"
                      Name="scrollViewer1" 
                      HorizontalAlignment="Stretch">
            <StackPanel 
                Margin="3,3,3,3"
                Background="Transparent"
                VerticalAlignment="Stretch"
                Name="activityStackPanel"
                HorizontalAlignment="Stretch">
            </StackPanel>
        </ScrollViewer>
    </Grid>
    <Button Content="Button" Grid.Row="2" Height="23" HorizontalAlignment="Left" Margin="12,0,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
    <Button Content="Button" Grid.Row="2" Height="23" HorizontalAlignment="Left" Margin="141,0,0,0" Name="button2" VerticalAlignment="Top" Width="75" Click="button2_Click" />
    <Label Content="Label" Grid.RowSpan="2" Height="28" HorizontalAlignment="Left" Margin="34,0,0,0" Name="label1" VerticalAlignment="Top" />
</Grid>

namespace WpfApplication10
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            int N = 100;
            //var r = new ActivityStatisticItem("111", "222", DateTime.Now, "333", 1);
            for (int i = 0; i < N; i++)
            {
                activityStackPanel.Children.Add(new UserControl1());
            }

            label1.Content = activityStackPanel.Children.Count;
        }

        private void button2_Click(object sender, RoutedEventArgs e)
        {
           activityStackPanel.Children.Clear();

            label1.Content = activityStackPanel.Children.Count;

            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
        }
    }
}
<UserControl x:Class="WpfApplication10.UserControl1"
      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" 
         Background="Transparent"
         Margin="0,2,0,2"
         MinHeight="80"
         MinWidth="130"
         MaxHeight="80">
<Grid Width="441">
    <Grid.RowDefinitions>
        <RowDefinition Height="40" Name="rowTop" />
        <RowDefinition Height="40" Name="rowBottom"/>
    </Grid.RowDefinitions>
    <Border BorderBrush="Gray" 
            BorderThickness="1" 
            HorizontalAlignment="Stretch" 
            Background="LightGreen"
            Name="contactPanel" 
            CornerRadius="3,3,3,3"
            VerticalAlignment="Stretch" Panel.ZIndex="1" >
        <Grid
            VerticalAlignment="Stretch" 
            Name="grid1" 
            Margin="3,0,3,0"
            HorizontalAlignment="Stretch">

            <Label Content="Contact" Height="15" HorizontalAlignment="Left" Margin="15,3,0,0" Name="headerLabel" Padding="0" VerticalAlignment="Top" FontSize="10" FontWeight="DemiBold"/>
            <Label Content="00/00/0000 00:00:00" Height="15" HorizontalAlignment="Left" Margin="13,18,0,0" Name="timeLabel" Padding="0" VerticalAlignment="Top" FontSize="10" Width="100" FontWeight="DemiBold" />
            <Label Content="00:00:00" Height="15" HorizontalAlignment="Right" Margin="0,18,0,0" Name="durationLabel" Padding="0" VerticalAlignment="Top" FontSize="10" Width="38" FontWeight="DemiBold"/>

            <!--<Image Height="12" HorizontalAlignment="Left" Margin="0,3,0,0" Name="directionPictureBox" Stretch="Fill" VerticalAlignment="Top" Width="12"  />
            <Image Height="12" HorizontalAlignment="Right" Margin="0,20,41,0" Name="timerImage" Stretch="Fill" VerticalAlignment="Top" Width="12"          />
            <Image Height="12" HorizontalAlignment="Left" Margin="0,20,0,0" Name="dateTimeImage" Stretch="Fill" VerticalAlignment="Top" Width="12"       />-->


        </Grid>
    </Border>
    <Border BorderBrush="Gray" 
            BorderThickness="1,0,1,1" 
            Grid.Row="1" 
            Background="White"
            HorizontalAlignment="Stretch" 
            Margin="10,0,10,0" 
            Name="detailsPanel" 
            CornerRadius="0,0,3,3"
            VerticalAlignment="Stretch">
        <Grid HorizontalAlignment="Stretch" 
              Name="grid2" 
              Margin="3,0,3,0"
              VerticalAlignment="Stretch">
            <Label Content="Label" Height="15" HorizontalAlignment="Stretch" FontSize="9" Padding="0" Margin="0,3,0,0" Name="numberRadLabel" VerticalAlignment="Top" />
            <Label Content="Label" Height="15" HorizontalAlignment="Stretch" FontSize="9"  Padding="0" Margin="0,18,0,0" Name="queueRadLabel" VerticalAlignment="Top" />

        </Grid>
    </Border>
</Grid>

In user control i have only

         public UserControl1()
         {
            InitializeComponent();
         }
like image 930
Andriy Khrystyanovich Avatar asked Jul 01 '11 12:07

Andriy Khrystyanovich


2 Answers

I want to release memory immediately.

Don't. Trust GC.

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

Don't. Trust GC.

After 5 - 10 min memory releases

Didn't I say trust GC?


  • Garbage collection model will make sure the unwanted managed memory in your system is released (which includes almost all of your controls memory). It uses an algorithm for optimising which includes generations, free memory available, possibly CPU available... so GC.Collect() will interfere with it.

  • GC.Collect() is asynchronous so no immediate effect.

  • The only resource you need to be careful is the unmanaged resource which usually is handled by Dispose Pattern. Otherwise don't mess with GC, it does its job very well.

like image 174
Aliostad Avatar answered Oct 08 '22 00:10

Aliostad


GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

This is a surefire way of forcing non-GCable objects into Gen2 prematurely, thus increasing your memory footprint for a longer period of time, for no good reason.

As Aliostad said: don't!

like image 42
Dan Puzey Avatar answered Oct 07 '22 23:10

Dan Puzey