I made a 64-bit WPF test app. With my app running and with Task Manager open, I watch my system memory usage. I see I'm using 2GB, and I have 6GB available.
In my app, I click an Add button to add a new 1GB byte array to a list. I see my system memory usage increases by 1GB. I click Add a total of 6 times, filling the 6GB of memory I had available when I started.
I click a Remove button 6 times to remove each array from the list. The removed byte arrays should not be referenced by any other object in my control.
When I Remove, I don't see my memory go down. But that's OK with me, because I understand that GC is non-deterministic and all that. I figure the GC WILL collect as needed.
So now with memory looking full, but expecting the GC to collect when needed, I Add again. My PC starts slipping in and out of a disk thrashing coma. Why didn't the GC collect? If that wasn't the time to do it, when is?
As a sanity check, I have a button to force GC. When I push that, I quickly get 6GB back. Doesn't that prove my 6 arrays were not being referenced and COULD have been collected had the GC knew/wanted to?
I've read a lot that says I shouldn't call GC.Collect() but if GC doesn't collect in this situation, what else can I do?
private ObservableCollection<byte[]> memoryChunks = new ObservableCollection<byte[]>();
public ObservableCollection<byte[]> MemoryChunks
{
get { return this.memoryChunks; }
}
private void AddButton_Click(object sender, RoutedEventArgs e)
{
// Create a 1 gig chunk of memory and add it to the collection.
// It should not be garbage collected as long as it's in the collection.
try
{
byte[] chunk = new byte[1024*1024*1024];
// Looks like I need to populate memory otherwise it doesn't show up in task manager
for (int i = 0; i < chunk.Length; i++)
{
chunk[i] = 100;
}
this.memoryChunks.Add(chunk);
}
catch (Exception ex)
{
MessageBox.Show(string.Format("Could not create another chunk: {0}{1}", Environment.NewLine, ex.ToString()));
}
}
private void RemoveButton_Click(object sender, RoutedEventArgs e)
{
// By removing the chunk from the collection,
// I expect no object has a reference to it,
// so it should be garbage collectable.
if (memoryChunks.Count > 0)
{
memoryChunks.RemoveAt(0);
}
}
private void GCButton_Click(object sender, RoutedEventArgs e)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}