Visual Basic.NET - Como liberar memoria tras crear graficos e imagenes

 
Vista:
sin imagen de perfil
Val: 10
Ha aumentado su posición en 7 puestos en Visual Basic.NET (en relación al último mes)
Gráfica de Visual Basic.NET

Como liberar memoria tras crear graficos e imagenes

Publicado por seba64 (6 intervenciones) el 16/02/2020 18:39:57
Saludos.

Estoy empezando y llevo 2 días en vb.net.
Lo primero que hice (lo único que he hecho) es dibujar unas líneas y rectángulos. Hasta el momento Bién, pero se me ocurre que toda esa memoria utilizada debe liberarse y quisiera preguntar a quienes hayan trabajado en esto acerca de cómo dónde y cúando se debería dejar libre la memoria.

Si uso:

Dim oGrafico As Graphics
oGrafico = form1.CreateGraphics

y lo mismo para otros gráficos, lápices e imágenes declarados. Cómo libero la memoria y si está bien que la declaración esté en un módulo o si debería estar en el formulario o como.
Muchas gracias por leer y de antemano por su ayuda.
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder
Imágen de perfil de Phil Rob
Val: 3.353
Oro
Ha mantenido su posición en Visual Basic.NET (en relación al último mes)
Gráfica de Visual Basic.NET

Como liberar memoria tras crear graficos e imagenes

Publicado por Phil Rob (1554 intervenciones) el 17/02/2020 09:31:58
Hola,

Quizá este puede te ayudar :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Dim MiGraphic As Graphics
Dim MiCadraGraphics As Panel
Private Sub UnProcedimiento()
 
    MiCadraGraphics = New Panel
    MiCadraGraphics.Top = 50
    MiCadraGraphics.Left = 50
    MiCadraGraphics.Height = 500
    MiCadraGraphics.Width = 500
    MiCadraGraphics.BackColor = Drawing.Color.White
 
    Me.Controls.Add(MiCadraGraphics)   ' Me o el Form que gusta
 
    MiGraphic = Me.MiCadraGraphics.CreateGraphics()
 
    ' ... ... ...
 
 
    ' En otro procedimiento, cuando no es mas necesario el dibujo
    Me.Controls.RemoveByKey("MiCadraGraphics")
    Me.MiCadraGraphics.Dispose()
 
    ' ... ... ...

Que tenga un buen dia
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
2
Comentar
sin imagen de perfil
Val: 10
Ha aumentado su posición en 7 puestos en Visual Basic.NET (en relación al último mes)
Gráfica de Visual Basic.NET

Como liberar memoria tras crear graficos e imagenes

Publicado por seba64 (6 intervenciones) el 17/02/2020 15:57:15
Muchas Gracias y un buen día para ti también
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 10
Ha aumentado su posición en 7 puestos en Visual Basic.NET (en relación al último mes)
Gráfica de Visual Basic.NET

Como liberar memoria tras crear graficos e imagenes

Publicado por seba64 (6 intervenciones) el 18/02/2020 03:02:49
Hola, He tratado haciendo lo que me indicas, pero me no funcionó

Explico.más o menos como es mi proyecto.
Todo mi código está en un módulo y mi lienzo es un formulario (cualquiera)

defino el gráfico al inicio del modulo, y también dos lapices

1
2
3
4
Module Module1
    Dim oGrafico As Graphics
    Dim lapiz1 As Pen
    Dim lapiz2 As Pen

Tengo una función que dibuja según los parámetros que són el formulario en que se dibuja y el color

1
2
3
4
5
Sub DrawLineqs(formulario As Object, colorMarcas As Color)
    oGrafico = formulario.CreateGraphics
    lapiz1 = New Pen(colorMarcas , 1)
    oGrafico.DrawRectangle(lapiz1 , X1 - 1, Y1 - 1, rw + 2, rh + 2)
End Sub

Inserté una función liberar, que es llamada al cerrar la aplicación, según las indicaciones del estimado Phil Rob.

1
2
3
4
Sub liberar(formulario As Object)
    formulario.Controls.RemoveByKey("oGrafico")
    oGrafico.Dispose()
End Sub

En la primera línea me da duda si lo he puesto bien y si tiene sentido.
En la segunda línea me da un error que habla de una referencia nula.
[indent]System.MissingMemberException: 'Public member 'oGrafico' on type 'Form2' not found.'
System.NullReferenceException: 'Object reference not set to an instance of an object.'


Y fin del código
1
End Module
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de Phil Rob
Val: 3.353
Oro
Ha mantenido su posición en Visual Basic.NET (en relación al último mes)
Gráfica de Visual Basic.NET

Como liberar memoria tras crear graficos e imagenes

Publicado por Phil Rob (1554 intervenciones) el 18/02/2020 11:36:22
Hola Seba,

Este es tu codigo rectificado :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Sub liberar(ByVal formulario As Form)    ' y no Object porque sabemos que este es un Form
        '      formulario.Controls.RemoveByKey("oGrafico") 'no existe Controls en este Form porque dibujas directo sobre
        Try       ' Try por que error si clock el buton 3Borrar" antes el buton "Llenar"
            formulario.Dispose()
            lapiz1.Dispose()   ' Dispose para cada objecto iniciar con New
        Catch
        End Try
 
        '      oGrafico.Dispose()
    End Sub
 
    Sub DrawLineqs(ByVal formulario As Form, ByVal colorMarcas As Color)  ' !!! Form
        oGrafico = formulario.CreateGraphics
        lapiz1 = New Pen(colorMarcas, 1)
        '       oGrafico.DrawRectangle(lapiz1, X1 - 1, Y1 - 1, rw + 2, rh + 2)  No sé variables x1, y1, rw y rh
        ' Entonces, pongo valores arbitrarios
        oGrafico.DrawRectangle(lapiz1, 10, 10, 200, 100)
    End Sub
 
    Private Sub BLlenarSegundario_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BLlenarSegundario.Click
        FSegundario.Show()   ' Primero, mostrar el Form
        DrawLineqs(FSegundario, Color.Red)
    End Sub

Adjunto mi proyecto de probas para tu testar.

Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Como liberar memoria tras crear graficos e imagenes

Publicado por Nacho (56 intervenciones) el 18/02/2020 22:21:49
No son correctas las indicaciones de Phil Rob. La MSDN lo explica perfectamente. Dice:

Normalmente, el objeto Graphics que se recupera a través del método CreateGraphics no se debería conservar una vez procesado el mensaje actual de Windows, ya que cualquier elemento pintado con ese objeto se borrará con el siguiente mensaje de WM_PAINT. Por lo tanto, no puede almacenar en caché el objeto Graphics para su reutilización, excepto para usar métodos no visuales como Graphics.MeasureString. En su lugar, debe llamar a CreateGraphics cada vez que desee usar el Graphics objeto y, a continuación, llamar a Dispose cuando termine de usarlo.

Tienes que llamar el Dispose y el CreateGraphics dentro de la misma función, no en otra que llames luego.

Sólo puedes conservar el objeto Graphics si no lo usas para pintar nada, porque entonces no tiene pillado el HDC de la ventana. Windows pinta en una ventana a través de un HDC. Cuando llamas a CreateGraphics te pasa el HDC de esa ventana y si no lo sueltas no puede usarlo él.

Los lápices y otros elementos para pintar no tienes que liberarlos.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de Phil Rob
Val: 3.353
Oro
Ha mantenido su posición en Visual Basic.NET (en relación al último mes)
Gráfica de Visual Basic.NET

Como liberar memoria tras crear graficos e imagenes

Publicado por Phil Rob (1554 intervenciones) el 18/02/2020 23:07:24
Hola Nacho,

" Tienes que llamar el Dispose y el CreateGraphics dentro de la misma función, no en otra que llames luego. " es falso. Este es necesario que estas operaciones estén en misma alcance y este es el caso cuando los variables son generales del Form.

El objeto Graphics no tiene el método Dispose. En mi código, ejecuto Dispose para el contenedor del dibujo. Creo que este es suficiente.

Pero si tienes mejor código, envias lo …

Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Como liberar memoria tras crear graficos e imagenes

Publicado por Nacho (56 intervenciones) el 18/02/2020 23:54:28
Me importa un rábano que discutas lo que sé yo desde que programaba para el Windows 3.1. Lo que no puedes hacer nunca es discutir lo que dice la MSDN, a no ser que seas Mark Russinovich.

Repito, de la MSDN:

Normalmente, el objeto Graphics que se recupera a través del método CreateGraphics no se debería conservar una vez procesado el mensaje actual de Windows.

https://docs.microsoft.com/es-es/dotnet/api/system.windows.forms.control.creategraphics?view=netframework-4.8

Y lo más correcto de todo es usar el Graphics dentro de una función Paint, que se llamará el llegar a la cola de mensajes un mensaje WM_PAINT. No suele hacer falta crearlo en una función distinta.

https://docs.microsoft.com/es-es/dotnet/api/system.drawing.graphics?view=netframework-4.8

Propiedades de Graphics:

Clip
Obtiene o establece un Region que limita la región de dibujo de este Graphics.

ClipBounds
Obtiene una estructura RectangleF que delimita la región de recorte de este Graphics.

CompositingMode
Obtiene un valor que especifica cómo se dibujan las imágenes compuestas en este Graphics.

CompositingQuality
Obtiene o establece la calidad de representación de las imágenes compuestas que se dibujan en este Graphics.

DpiX
Obtiene la resolución horizontal de este Graphics.

.....

Métodos de Graphics:

AddMetafileComment(Byte[])
Agrega un comentario al Metafile actual.

BeginContainer()
Guarda un contenedor de gráficos con el estado actual de este Graphics y abre y usa un nuevo contenedor de gráficos.

BeginContainer(Rectangle, Rectangle, GraphicsUnit)
Guarda un contenedor de gráficos con el estado actual de este Graphics y abre y usa un nuevo contenedor de gráficos con la transformación de escala especificada.

BeginContainer(RectangleF, RectangleF, GraphicsUnit)
Guarda un contenedor de gráficos con el estado actual de este Graphics y abre y usa un nuevo contenedor de gráficos con la transformación de escala especificada.

Clear(Color)
Borra toda la superficie de dibujo y la rellena con el color de fondo especificado.

CopyFromScreen(Int32, Int32, Int32, Int32, Size)
Realiza una transferencia de bloque de bits de los datos de color, correspondientes a un rectángulo de píxeles, desde la pantalla a la superficie de dibujo de Graphics.

CopyFromScreen(Int32, Int32, Int32, Int32, Size, CopyPixelOperation)
Realiza una transferencia de bloque de bits de los datos de color, correspondientes a un rectángulo de píxeles, desde la pantalla a la superficie de dibujo de Graphics.

CopyFromScreen(Point, Point, Size)
Realiza una transferencia de bloque de bits de los datos de color, correspondientes a un rectángulo de píxeles, desde la pantalla a la superficie de dibujo de Graphics.

CopyFromScreen(Point, Point, Size, CopyPixelOperation)
Realiza una transferencia de bloque de bits de los datos de color, correspondientes a un rectángulo de píxeles, desde la pantalla a la superficie de dibujo de Graphics.

CreateObjRef(Type)
Crea un objeto que contiene toda la información relevante necesaria para generar un proxy utilizado para comunicarse con un objeto remoto.
(Heredado de MarshalByRefObject)

Dispose()
Libera todos los recursos utilizados por este Graphics. Y añado yo, libera el HDC de la ventana, para que pueda usarlo el Windows.

.......


Difícilmente vas a encontrar mejores ejemplos de código que los que pone Microsoft en la MSDN

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void FromImageImage1(PaintEventArgs e)
{
    // Create image.
    Image imageFile = Image.FromFile("SampImag.jpg");
 
    // Create graphics object for alteration.
    Graphics newGraphics = Graphics.FromImage(imageFile);
 
    // Alter image.
    newGraphics.FillRectangle(new SolidBrush(Color.Black), 100, 50, 100, 100);
 
    // Draw image to screen.
    e.Graphics.DrawImage(imageFile, new PointF(0.0F, 0.0F));
 
    // Release graphics object.
    newGraphics.Dispose();
}

https://docs.microsoft.com/es-es/dotnet/api/system.drawing.graphics.dispose?view=netframework-4.8

Come verás, en ese ejemplo llama al CreateGraphics dentro de una función Paint.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
-2
Comentar
sin imagen de perfil
Val: 10
Ha aumentado su posición en 7 puestos en Visual Basic.NET (en relación al último mes)
Gráfica de Visual Basic.NET

Como liberar memoria tras crear graficos e imagenes

Publicado por seba64 (6 intervenciones) el 19/02/2020 04:32:53
Yo entiendo que los foros son para discutir y consultar y yo he aclarado que estoy iniciando y lo he hecho creando una función en base a un código simple que encontré en algún lugar de msdn. Consulté porque creo importante liberar la memoria y yo no tenía eso en mi función. Ahora no me dejan nada claro excepto que al parecer se debe disponer del objeto dentro de la misma función, o eso creo haber entendido, porque yo no voy a discutir con microsoft aunque nunca me ha aclarado al 100%.

Para aclarar quisiera si me pueden responder las siguientes 4 preguntas-

1. Al cerrarse la aplicación, visual basic o el ejecutable compilado, ¿Acaso no eliminan todas las variables generadas en la memoria?
2. Declaré el grafico y los lapices en el módulo, no en funciones, no en formularios. ¿está mal?
3. Según la gráfica, ¿Por qué al utilizar dispose utiliza más memoria de proceso? (es broma)
4. Aunque no me queda claro todo lo que mencionas, sería rebueno tener el HDC o llevar un arreglo de los objetos que se van generando para después realizar otras operaciones sobre ellos. Yo sólo quiero tirar algunas líneas, pero en mi busqueda vi ejemplos que generaban gráficos e imágenes que se podían mover y cambiar de tamaño.pero yo no voy por nada tan complejo.
4.1. No entendí lo de la función paint,sobre todo lo de mensaje WM_PAINT. Aunque mi función es llamada en el evento paint por algunos formularios.
4.2. he visto los enlaces, se agradece por ellos. He visto que los códigos son similares a los míos y como no, si tienen el mismo origen. Se ve que sabes y me hubiera gustado que me respondieras a mi en lugar de a Phil.


Comento que de todo lo que he visto hasta el momento, que tampoco es tanto, sólo en un ejemplo vi la palabra Dispose y esa fue la razón por lo que inicié este hilo en el foro.


Se agradece a ambos y saludos que estén muy bien.

O/
/|
/|
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Como liberar memoria tras crear graficos e imagenes

Publicado por Nacho (56 intervenciones) el 19/02/2020 17:30:32
La plataforma .Net tiene un recolector de basuras. Microsoft dice que no hay que liberar nada y recomienda no hacerlo, salvo alguna que otra excepción.

1- Una aplicación que sólo haga uso de código administrado en principio no tiene que liberar nada. El garbage collector elimina lo que sobre en el momento que lo considere oportuno, tampoco tiene que ser al cerrar la aplicación.

2- Siempre se recomienda crear lo máximo posible dentro de una función, o sea, usar la máxima cantidad de memoria local y la menor global. Tienes montones de páginas en internet tratando del tema.

3- Un error recurrente a la hora de programar es dejar memoria reservada sin liberar. Es algo que les pasa a todos. Por eso una prueba que no se debe dejar de hacer es comprobar la cantidad de memoria que usa un programa y ver que no va continuamente subiendo hasta llegar a los 7 gigas o más (es en serio).

4- No puedes quedarte con un HDC. Cuando llamas a CreateGraphics no creas ningún objeto. Lo que hace el Windows es pasarte el HDC de un objeto ya creado por él, el DC de la ventana. Te lo presta, y tienes que soltarlo al acabar de procesar el mensaje WM_PAINT para poder usarlo él.

4.1- Algo que no acaban de entender muchos porgramadores de Windows es qué es eso de los mensajes. Se dice que Windows es un sistema operativo orientado a mensajes. Windows se comunica con los programas de usuario básicamente a través de mensajes. Cuando hay que repintar una ventana manda a la aplicación un WM_PAINT. Si tienes un temporizador manda un WM_TIMER periódico. Cuando aprietas el botón izquierdo del ratón manda un WM_LBUTTONDOWN. Así hasta los más de mil que hay. Los mensajes se procesan en la función de ventanas, que tiene cualquier programa gráfico en Windows, aunque no la veas. Cuando se produce un evento, pulsado un botón del ratón, por ejemplo, a tu aplicación puede llegar un WM_LBUTTONDOWN Ese mensaje lo procesa la función de ventanas. Si en tu programa quieres hacer algo cuando pulses un botón, dentro de la parte de ese mensaje habrá una llamada a alguna función de tu programa. Con el WM_PAINT pasa lo mismo. Si tienes una función Paint definida, en el código del programa que no ves habrá algo así como:

1
2
3
4
5
6
7
8
9
10
11
12
13
LRESULT CALLBACK WindowProc( _In_ HWND   hwnd,  _In_ UINT   uMsg,  _In_ WPARAM wParam, _In_ LPARAM lParam)
{
    switch (uMsg)
    {
          case WM_PAINT :
                HDC hdc = GetDC(hwnd);
                PaintEventArgs e = new PaintEventArgs();
                e.Graphics = hdc;
                TuFuncionPaint(sender, e);
                ReleaseDC(hdc);
        break;
    }
}

GetDC hace lo mismo de CreateGraphics. ReleaseDC, lo mismo que graphics.Dispose.

4.2- Le respondí a él cuando respondió a lo que dije yo.

Hay cosas que en .Net hay que liberar siempre. Cosas más bien raras pero las hay. Por eso es conveniente mirar si dice Microsoft que hay que liberarlas o no.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 10
Ha aumentado su posición en 7 puestos en Visual Basic.NET (en relación al último mes)
Gráfica de Visual Basic.NET

Como liberar memoria tras crear graficos e imagenes

Publicado por seba64 (6 intervenciones) el 19/02/2020 23:15:27
Vale gracias ;-)
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar