¿Pérdida de memoria de C # WPF BitmapSource?

Estoy desarrollando un programa de BlackJack que muestra una mesa de BlackJack, cartas, etc. El plan es que jugará miles de manos una tras otra con una estrategia automatizada.

Tengo un UserControl PlayerSeat que contiene un ItemsControl vinculado a un ObservableCollection. Esta clase CardInHand contiene un BitmapSource denominado CardImage. Cuando la instancia está embalada, carga la imagen de la tarjeta desde los recursos utilizando el siguiente código:

[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;
}

El problema es que después de ejecutar ~ 500 rondas (~ 4000 manos o ~ 10000 tarjetas) termino con un error GDI + y la aplicación ocupa ~ 400 MB de RAM. Este crece rápidamente y está relacionado con el número de manos que se han jugado.

DeleteObject () es algo que encontré en otro sitio que decía que esta es la mejor manera de liberar los recursos del mapa de bits. PODRÍA tener un pequeño efecto, pero no lo que estoy buscando. También probé Dispose ().

Otro sitio dijo que tenía que ver con el enlace de ItemsSource. Quité la atadura y la memoria aún crecía. A la inversa, dejé el enlace y eliminé el código que genera el mapa de bits. Jugó 40,000 rondas y no creció sustancialmente (tal vez + 20 MB durante los 40 minutos que estuvo funcionando).

El ObservableCollection es Clear () ed después de cada ronda. Intenté anular la colección, CardInHand y la propiedad BitmapSource, sin éxito.

¿Cómo puedo permitir que estas imágenes se muestren en la pantalla, pero también asegurarme de que sus objetos se destruyan correctamente después de que ya no sean necesarios?

Gracias por tu tiempo.

preguntado el 28 de agosto de 11 a las 02:08

1 Respuestas

Primero que nada, solo tienes 52 cartas. Simplemente cree las imágenes por adelantado y guárdelas durante la vida útil de la aplicación. Después de todo, es un juego de Black Jack; Es seguro asumir que cada tarjeta será necesaria en un momento u otro.

Dicho esto, existe un problema con la creación BitmapSource objetos de arroyos. los byte[] retenido por la corriente no se libera cuando la corriente se elimina. Vea mi propia pregunta aquí. La única razón por la que no voté para cerrar como duplicado es porque creo que debería crear las tarjetas una vez y terminar con ellas en lugar de crear estas imágenes más de 10,000 veces.

contestado el 23 de mayo de 17 a las 15:05

Esto tiene sentido. Si genero un BitmapSource al iniciar la aplicación, debería poder hacer referencia a eso, ¿correcto? Solo almacenará una referencia al BitmapSource original en la clase CardInHand y no duplicará los datos, ¿verdad? - César Kabalan

@Caesar: Sí, solo créelos al inicio y guárdelos en un diccionario o algo así. Asigne un tipo de tarjeta a la imagen usando una enumeración o adminístrelos como desee, simplemente no cree uno nuevo cada vez que sea necesario. - Ed s.

Ejemplo clásico del Patrón de peso mosca aquí. - Cameron MacFarland

Gracias a todos. Esto funcionó perfectamente. Terminé haciendo lo que dijo Ed S. ¡Gracias de nuevo! - César Kabalan

Tal vez me esté perdiendo algo aquí, pero parece que en la pregunta, el BitmapSource is no creado en base a una secuencia, pero basado en un identificador de mapa de bits recuperado de un Bitmap objeto. - OR Mapper

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.