Pregunta

Estoy sufriendo de un OutOfMemoryException al obtener una imagen de un ImageList he sido incapaz de encontrar una solución adecuada al problema.

Tengo un control ListView personalizado, que se ha unido a él un evento para el dibujo de ListViewItems. Esto requiere entonces un método estático que está diseñado para sacar el artículo.

En un ListView de alrededor de 300 artículos, que estamos recibiendo la memoria saltar alrededor de 100 Mb cada vez que se desplaza el ListView. El código erróneo ha sido rastreado a lo siguiente:

Image image = item.ImageList.Images[item.ImageKey];
if (image != null)
{
    Size imageOffset = new Size((bounds.Width - image.Width) / 2, 2); 
    Point imagePosition = bounds.Location + imageOffset;
    graphics.DrawImageUnscaled(image, imagePosition);
}

Parece (ciertamente en WinXP) que la recolección de basura no está funcionando correctamente, causando la memoria en espiral. Hemos intentado añadir un image.Dispose () directamente después del bloque de código para solucionar el problema, pero que no tiene ningún efecto.

La única solución que he logrado encontrar hasta el momento, se encuentra al final del método estático para llamar GC.Collect (). El problema con esto sin embargo es que hace entonces que el ListView para volver a pintarse lentamente y se llega a artefactos en la pantalla mientras intenta volver a dibujar.

¿Alguien más ha experimentado esto? O sabe de alguna solución?

¿Fue útil?

Solución

¿Está desechando graphics? Además, se deshaga su imagen como usted ha mencionado a continuación, lo que se necesita para asegurarse de que se saca de la ImageList o va a causar más problemas. Lo qué formato son las imágenes?

En general, cuando usted sale de problemas de memoria cuando se trata de imágenes, su problema será o bien algún método no le gusta un poco de formato de imagen, o 9/10 veces, se entendió mal el ciclo de vida de uno de los objetos gráficos.

  • Marque todo su uso de Graphics y ponerlos en bloques using.
  • Compruebe su ciclo de vida Image y tener cuidado con la copia de ellos, disponiéndolos, cerrando las corrientes subyacentes, etc.
  • Carga un administrador de memoria (VS2008 tiene uno interno) y ver lo que no está siendo limpiado muy bien.

EDIT:

Esta es la mejor opción que puedo encontrar, usar ImageList.Draw(graphics, x, y, width, height, index). Esto utilizará la manija interna en lugar de crear una copia de la imagen.

Otros consejos

He logrado resolver este problema en mi solicitud.

Jason tiene la respuesta, usted tiene que asegurarse de que utiliza "utilizando" bloques, o su equivalente.

Yo uso VB, y el equivalente era utilizar Try ... Catch ... Finally siempre he creado un nuevo mapa de bits, llamando Bitmap.Dispose y establecer el mapa de bits = nada en la parte de "último".

Esto parece ser un problema muy común, a juzgar por las horas que he pasado tratando de Google esto. El código de abajo también permite que cualquier imagen para conservar su relación de aspecto cuando se reduzca a una miniatura, otra cuestión que parece ser difícil de Google!

Código:

Private Function AspectedImage(ByVal ImagePath As String, ByVal SizeWanted As Integer) As Image

    Dim myBitmap, WhiteSpace As System.Drawing.Bitmap
    Dim myGraphics As Graphics
    Dim myDestination As Rectangle
    Dim MaxDimension As Integer
    Dim ReductionRatio As Double

    Try

        'create an instance of bitmap based on a file
        myBitmap = New System.Drawing.Bitmap(ImagePath)



        'create a new square blank bitmap the right size
        If myBitmap.Height >= myBitmap.Width Then MaxDimension = myBitmap.Height Else MaxDimension = myBitmap.Width
        ReductionRatio = SizeWanted / MaxDimension
        WhiteSpace = New System.Drawing.Bitmap(SizeWanted, SizeWanted)

        'get the drawing surface of the new blank bitmap
        myGraphics = Graphics.FromImage(WhiteSpace)

        'find out if the photo is landscape or portrait
        Dim WhiteGap As Double

        If myBitmap.Height > myBitmap.Width Then 'portrait
            WhiteGap = ((myBitmap.Width - myBitmap.Height) / 2) * -1
            myDestination = New Rectangle(x:=CInt(WhiteGap * ReductionRatio), y:=0, Width:=Int(myBitmap.Width * ReductionRatio), Height:=Int(myBitmap.Height * ReductionRatio))
        Else 'landscape
            WhiteGap = ((myBitmap.Width - myBitmap.Height) / 2)
            'create a destination rectangle
            myDestination = New Rectangle(x:=0, y:=CInt(WhiteGap * ReductionRatio), Width:=Int(myBitmap.Width * ReductionRatio), Height:=Int(myBitmap.Height * ReductionRatio))
        End If

        'draw the image on the white square
        myGraphics.DrawImage(image:=myBitmap, rect:=myDestination)
        AspectedImage = WhiteSpace

    Catch ex As Exception
        myBitmap = New System.Drawing.Bitmap("")
        AspectedImage = New System.Drawing.Bitmap(4, 4)
        ImageBufferExceeded = True
        MsgBox("Image Buffer exceeded, too many images in memory. If the one(s) you want can't be seen, please restart the application and navigate straight to your images")
    Finally
        myBitmap.Dispose()
        myBitmap = Nothing
        WhiteSpace = Nothing
    End Try

End Function
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top