none
Memoria insuficiente en matriz de bitmaps

    Pregunta

  • Buenos días amigos del foro,

      Tengo dos matrices de tipo bitmap para una animación, pero al crearlas llega un momento en el que el ordenador me da un error de Memoria insuficiente. ¿Cómo podría ampliar la memoria? o si saben alguna alternativa a una matriz de bitmaps en el que el programa no diera problemas, se lo agradecería. Las matrices contienen unos 600 bitmaps o más.

    Gracias de antemano por su ayuda. Un saludo.

    sábado, 7 de enero de 2017 10:45

Respuestas

  • No veo claro lo del Dispose. La clase System.Array no es IDisposable, luego no puedes llamar a su método Dispose. En cambio, System.Drawing.Bitmap sí que tiene un método Dispose, que hereda de Image. En este caso, sí que puedes (y debes) llamar al Dispose, lo cual liberará todos los recursos no-gestionados consumidos por el Bitmap. La memoria gestionada se liberará automáticamente cuando el Garbage Collector recoja los objetos inalcanzables. No se me ocurre un motivo para que te falle después de varias veces, salvo que el problema esté en el mecanismo que usas para cargar os bitmaps, que esté usando algún otro objeto que requiera llamar al Dispose y no lo estés llamando.

    Otra cosa que podría pasar, aunque me parece poco probable, es que se te esté fragmentando el Large Object Heap (el sitio donde se asignan los objetos grandes, y me imagino que a estos efectos tus bitmaps se consideran "grandes"). El Heap normal de los objetos pequeños se reorganiza para juntar los huecos libres pequeños cuando se necesita para asignar memoria a un objeto más grande. Pero en cambio el Heap de objetos grandes no se reorganiza (porque sería muy costoso mover los bloques grandes de memoria), y puede ser que a pesar de que haya suficiente memoria libre en total, te dé un error de falta de memoria al tratar de asignar un nuevo objeto si no existe ningún hueco suficientemente grande para él. Para aliviar este problema, si es posible procura reducir la presión sobre el gestor de memoria, reutilizando los objetos que se pueda (tales como los bitmaps) en lugar de destruirlos y asignar nuevos objetos. Si esto no se puede conseguir, tal vez tengas que recurrir a no mantener tantos bitmaps cargados en memoria, salvando a disco los que no quepan en la RAM.

    domingo, 8 de enero de 2017 22:19

Todas las respuestas

  • Multiplica el tamaño de cada bitmap por el número de bitmaps y eso te dará la memoria necesaria. Por ejemplo, si tus bitmaps son de 2000x2000 pixels y 32 bits por pixels, entonces cada bitmap mide 16 megabytes. Si lo multiplicas por los 600 bitmaps, resulta que se requieren 9,6 Gigabytes para almacenarlos. Si tienes un sistema de 32 bits, entonces no será capaz de manejar mas de 2 Gigabytes y te dará un error de memoria insuficiente. Por el contrario, si lo ejecutas en 64 bits, no habrá problemas a condición de que realmente tengas esa cantidad de memoria (virtual, no necesariamente física).
    sábado, 7 de enero de 2017 16:10
  • ¿Podría hacer una lista de bitmaps como Dim Lista As New List(of Bitmap)?
    Pero si dibujo en un bitmap bm y lo agrego a la lista, Lista.Add(bm) y vuelvo a dibujar en el mismo
    bitmap y lo vuelvo a agregar, Lista.Add(bm), al final al recorrer los Items de la lista, me sale el
    mismo dibujo.
    sábado, 7 de enero de 2017 20:11
  • Sí, podrías hacer un List(of Bitmap)... y tendrás la misma limitación de tamaño que con el array y un pelín más de ocupación de memoria.

    Recuerda que el Bitmap es un tipo-referencia, por lo tanto cada vez que lo copias (por ejemplo, haciendo Lista.Add(...)) lo que se copia es la referencia y no el contenido. Por lo tanto todas las copias apuntan al mismo contenido y se a través de todas ellas se ve el mismo bitmap. En este caso, la ocupación de memoria es muy pequeña y puedes meter todos los bitmaps que quieras en la lista, pero no sirve para nada porque todo lo que has metido son referencias que apuntan al mismo bitmap. Para evitarlo, acuérdate de reinicializar la variable bm apuntándola a un "New Bitmap()" cada vez que la vayas a usar para un nuevo dibujo. Esto evitará el problema de que en todos te salga el mismo dibujo, pero lógicamente todos los distintos dibujos tendrán que guardarse en memoria y volverás a tener la misma limitación de capacidad que con el array.

    sábado, 7 de enero de 2017 20:24
  • Gracias por asesorarme de como funciona la memoria y tiene razón en los List de Bitmaps, lo he probado, pero me ha surgido lo siguiente:

    Como el espacio en memoria es limitado, en vez de dos matrices he creado una sola y he limitado más los píxeles
    y la cantidad de bitmaps, y parece que funciona. Aunque libere espacio en memoria con el Dispose en toda la matriz, si vuelvo a generar los bitmaps, a la cuarta vez que lo hago me da error de Memoria insuficiente. ¿Cómo podría liberar espacio para que pudiera generar y destruir los bitmaps, las veces que quiera? Mi programa consiste en transformar fotos o imágenes en esferas que dan vueltas. Gracias por ayudarme.

    domingo, 8 de enero de 2017 21:00
  • No veo claro lo del Dispose. La clase System.Array no es IDisposable, luego no puedes llamar a su método Dispose. En cambio, System.Drawing.Bitmap sí que tiene un método Dispose, que hereda de Image. En este caso, sí que puedes (y debes) llamar al Dispose, lo cual liberará todos los recursos no-gestionados consumidos por el Bitmap. La memoria gestionada se liberará automáticamente cuando el Garbage Collector recoja los objetos inalcanzables. No se me ocurre un motivo para que te falle después de varias veces, salvo que el problema esté en el mecanismo que usas para cargar os bitmaps, que esté usando algún otro objeto que requiera llamar al Dispose y no lo estés llamando.

    Otra cosa que podría pasar, aunque me parece poco probable, es que se te esté fragmentando el Large Object Heap (el sitio donde se asignan los objetos grandes, y me imagino que a estos efectos tus bitmaps se consideran "grandes"). El Heap normal de los objetos pequeños se reorganiza para juntar los huecos libres pequeños cuando se necesita para asignar memoria a un objeto más grande. Pero en cambio el Heap de objetos grandes no se reorganiza (porque sería muy costoso mover los bloques grandes de memoria), y puede ser que a pesar de que haya suficiente memoria libre en total, te dé un error de falta de memoria al tratar de asignar un nuevo objeto si no existe ningún hueco suficientemente grande para él. Para aliviar este problema, si es posible procura reducir la presión sobre el gestor de memoria, reutilizando los objetos que se pueda (tales como los bitmaps) en lugar de destruirlos y asignar nuevos objetos. Si esto no se puede conseguir, tal vez tengas que recurrir a no mantener tantos bitmaps cargados en memoria, salvando a disco los que no quepan en la RAM.

    domingo, 8 de enero de 2017 22:19
  • Hola, problema resuelto.

    Tenía usted razón, liberando memoria con el Dispose no tiene por qué dar error. Mi fallo ha sido no liberar memoria en la matriz Graphics, al hacer el Dispose en los Bitmaps y en los Graphics, no me da problemas. Muchas gracias y hasta otra.

    lunes, 9 de enero de 2017 10:31