ImageList / OutOfMemoryException Imagem

votos
4

Eu estou sofrendo de uma OutOfMemoryException quando a obtenção de uma imagem de um ImageList eu fui incapaz de encontrar uma solução adequada para o problema.

Eu tenho um controle personalizado ListView, que seja acompanhada de um evento para o desenho de ListViewItems. Isso, então, chama um método estático que é projetado para desenhar o item.

Para um ListView de cerca de 300 itens, nós estamos começando a memória saltar para cima em torno de 100Mb cada vez que o ListView é rolada. O código incorreto foi rastreou ao seguinte:

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 (certamente no WinXP) que a coleta de lixo não está funcionando corretamente, fazendo com que a memória em espiral. Nós tentamos adicionar um image.Dispose () logo após o bloco de código para corrigir o problema, mas que não tem qualquer efeito.

A única solução que conseguiram encontrar, até agora, está no final do método estático para chamar GC.Collect (). O problema com isso, porém, é que ele faz com que o ListView para re-pintar-se lentamente e você acaba ficando artefatos na tela enquanto ele tenta re-draw.

Tem mais alguém experimentou este? Ou sabe de uma solução alternativa?

Publicado 19/05/2009 em 14:00
fonte usuário
Em outras línguas...                            


2 respostas

votos
4

Você descartar graphics? Além disso, você dispor sua imagem como você mencionou, em seguida, você precisa se certificar de que é retirado do ImageList ou você vai causar mais problemas. O que formato são as imagens?

Em geral, quando você sair de problemas de memória, quando as imagens estão envolvidas, o problema será ou algum método não gosta de algum formato de imagem, ou 9/10 vezes, você entendeu mal o ciclo de vida de um dos objetos gráficos.

  • Verifique todo o seu Graphicsuso e colocá-los em usingblocos.
  • Verifique se o seu Imageciclo de vida e ter cuidado com copiá-los, descartá-los, fechando córregos subjacentes, etc.
  • Coloque-se um gerenciador de memória (VS2008 tem um embutido) e ver o que não está sendo limpado bem.

EDITAR:

Aqui é a melhor opção que eu posso encontrar, use ImageList.Draw(graphics, x, y, width, height, index). Isto irá usar a alça interna em vez de criar uma cópia da imagem.

Respondeu 20/05/2009 em 05:42
fonte usuário

votos
0

Eu consegui resolver este problema na minha aplicação.

Jason tem a resposta, você tem que ter certeza que você use "usando" blocos, ou seu equivalente.

Eu uso VB, e o equivalente era usar Try ... Catch ... Finally sempre que criou um novo bitmap, chamando Bitmap.Dispose e definindo o Bitmap = nada no "Finalmente" parte.

Este parece ser um problema muito comum, a julgar pelas horas que passei tentando Google isso. O código abaixo também permite que qualquer imagem para manter a sua relação de aspecto ao ser reduzidos para uma miniatura, uma outra questão que parece ser difícil para o 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
Respondeu 11/06/2009 em 20:08
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more