I'm developing a BlackJack program which shows a BlackJack Table, cards, etc. The plan is that it'll be playing thousands of hands one after another with an automated strategy.
I have a PlayerSeat UserControl which contains an ItemsControl bound to a ObservableCollection. This CardInHand class contains a BitmapSource named CardImage. When the instance is crated it loads the card image from resources using the following code:
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
private BitmapSource GenerateCardImage() {
Stream TempStream = this.GetType().Assembly.GetManifestResourceStream("BlackJack.Resources.CardImages.Card_" + m_Card.ShortTitle + ".gif");
System.Drawing.Bitmap sourceBMP = new System.Drawing.Bitmap(TempStream);
BitmapSource tempBitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
sourceBMP.GetHbitmap(),
IntPtr.Zero,
System.Windows.Int32Rect.Empty,
BitmapSizeOptions.FromWidthAndHeight(sourceBMP.Width, sourceBMP.Height)
);
TempStream.Dispose();
DeleteObject(sourceBMP.GetHbitmap());
return tempBitmapSource;
}
The problem is that after I run through ~500 rounds (~4000 hands or ~10000 cards) I end up with a GDI+ error and the application taking up ~400MB of RAM. This grows quickly and is related to the number of hands that have been played.
DeleteObject() is something I had found on another site which said that this is the best way to release the resources from the Bitmap. It's MIGHT be having a small affect, but not what I'm looking for. I've also tried Dispose().
Another site said it had to do with ItemsSource binding. I removed the binding and memory still grew. Inversely I left the binding and removed the code that generates the bitmap. It played 40,000 rounds and did not grow substantially (maybe +20MB over the 40min it was running).
The ObservableCollection is Clear()ed after every round. I've tried nulling the collection, the CardInHand, and the BitmapSource propery, to no avail.
How can I allow these images to display on the screen but also make sure their objects are propery destroyed after they're no longer needed?
Thank you for your time.
So first off, you only have 52 cards. Just create the images up front and keep them around for the life of the application. It is a Black Jack game after all; it is safe to assume that each card will be needed at one point or another.
That said, there is an issue with creating BitmapSource
objects from streams. The byte[]
held by the stream is not being freed when the stream is disposed. See my own question here. The only reason I didn't vote to close as a duplicate is because I think you should really just create the cards once and be done with it instead of creating these images 10,000+ times.
来源:https://stackoverflow.com/questions/7218721/c-sharp-wpf-bitmapsource-memory-leak