/ / .NET Memory Feak, use GC.Collet () o Don't - .net, vb.net, fugas de memoria, recolección de basura, creación de perfiles

Pérdida de memoria de .NET, use GC.Collet () o Don't - .net, vb.net, fugas de memoria, recolección de basura, creación de perfiles

Tengo el siguiente código con vb.net:

Public Async Function WriteData(buffer() As Byte, offset As Integer, count As Integer) As System.Threading.Tasks.Task
Try
Using data_writer = IO.WindowsRuntimeStreamExtensions.AsStreamForWrite(_outputStream)
Await data_writer.WriteAsync(buffer, offset, count)
Await data_writer.FlushAsync
End Using
Catch ex As Exception
Logger.Write(ex)
End Try
End Function

Llamo a la función WriteDate demasiado, peronote un aumento en la memoria cada vez que llamo a la función, ya que puede ver que el flujo de datawriter y el _outputStream están eliminados debido al uso de Using.

Cuando ejecuto el vs Profiler, el generador de perfiles me muestra que el 95% de la memoria está reservada en exceso por la matriz de bytes que es "buffer" en mi código.

1- ¿Ves algún problema en mi código? 2- ¿Cómo puedo borrar la matriz de bytes?

- Agregué el siguiente código a esa función después de la línea Await data_writer.FlushAsync

buffer = Nothing
GC.Collect()

Así que mi memoria no aumenta como antes, pero llamo demasiado a WriteData en mi aplicación, y leí que no se recomienda llamar a GC.Collect demasiado.

Sin llamar a GC.Collect, la memoria salta a 300 MB, con la memoria GC.Collect () no supera los 50 MB.

Por favor aconséjame.

Gracias

Respuestas

2 para la respuesta № 1

Este es un problema genérico de GC, no específico paraLlama o espera. Aunque ciertamente no ayuda a resolver el problema. El problema es que su búfer es demasiado grande, más de 85 KB. Demasiado grande para que el GC lo compacte fácilmente, por lo que se asigna en el montón de objetos grandes. Ahora no hay suficientes objetos pequeños en la generación 0 para activar una colección. El LOH solo se limpia durante una colección gen # 2, por lo que llamar a GC.Collect () es, de hecho, una solución alternativa.

Dos estrategias básicas para evitar tener que llamar.Recoger(). Primero, favorece fuertemente el uso de un búfer más pequeño, lo suficientemente pequeño como para asignarlo en gen # 0 Hacer pequeñas tareas siempre es mejor, la palabra clave Await realmente debería ayudar a hacer un cambio trivial en su código. Es difícil decirlo, no podemos ver a la persona que llama.

La segunda estrategia es reutilizar El buffer por lo que solo necesitas uno de ellos. La facilidad con la que depende depende en gran medida de cómo se vea la persona que llama.


2 para la respuesta № 2

Debes entender cómo funciona el GC antesintentas controlarlo Una recolección de basura es impulsada principalmente por "presión de memoria"; es decir, cuando a su programa le falta memoria para su uso inmediato, se producirá una recopilación para liberar algunos.

La razón por la que usa su memoria es de 300MB sin llamar GC.Collect es porque .NET no está bajo presión cuando ejecuta su código. Debido a que no está bajo presión, no pierde tiempo ejecutando una colección. Los 300 MB de memoria asignada no se están utilizando activamente, su código no es mágicamente más eficiente. porque estas llamando Collect - pero no hay razón para que .NET se arregle en ese momento.

Mi consejo sería: no llames. GC.Collect, a menos que tengas una específica y significativaRazón para reducir el uso de memoria de tu aplicación. Cuando sea necesario, el recolector de basura recolectará esa memoria (es probable que aumente su uso y luego vuelva a bajar a ~ 50 MB periódicamente).


0 para la respuesta № 3

Tuve el mismo problema, en otro escenario, con el servidor HTTP, pero encontré la solución real:

Nunca use AsStreamForWrite (), use WinPRTIOuputStream directamente (supongo que es posible, incluso en VB) AsStreamForWrite () crea una secuencia interna que solo se come la memoria (en varios casos) y nunca la libera.