Está en la página 1de 8

Control del consumo de recursos y mejora del

rendimiento
.NET Framework (current version)
Otras versiones

En este tema se describen varias propiedades en diferentes áreas de la arquitectura Windows


Communication Foundation (WCF) que trabajan para controlar el consumo de recursos y que afectan a
las mediciones del rendimiento.

Propiedades que restringen el consumo de recursos en WCF


Windows Communication Foundation (WCF) aplica las restricciones en ciertos tipos de procesos con
fines de seguridad o rendimiento.Estas restricciones adquieren dos formas básicas: cuotas y
aceleradores. Las cuotas son los límites que cuando se alcanzan o superan desencadenan una excepción
inmediata en algún punto del sistema. Los aceleradores son límites que no producen inmediatamente
una excepción.En su lugar, cuando se alcanza el límite del acelerador, el procesamiento continúa pero
dentro de los límites establecidos por ese valor.Este procesamiento limitado puede activar una
excepción en otra parte, pero esto depende de la aplicación.

Además de la distinción entre cuotas y aceleradores, algunas propiedades de restricción se encuentran


en el nivel de serialización, algunas en el nivel de transporte y algunas en el nivel de aplicación.Por
ejemplo, la cuota TransportBindingElement.MaxReceivedMessageSize, que implementan todos los
elementos de enlace de transporte proporcionados por el sistema, está establecida de forma
predeterminada en 65.536 bytes para impedir que los clientes malintencionados emprendan ataques de
denegación de servicio contra un servicio provocando el consumo excesivo de memoria.(Normalmente,
puede aumentar el rendimiento bajando este valor.)

Un ejemplo de una cuota de la serialización es la propiedad


DataContractSerializer.MaxItemsInObjectGraph, que especifica el número máximo de objetos que el
serializador serializa o deserializa en una única llamada al método ReadObject.Un ejemplo de un
acelerador en el nivel de aplicación es la propiedad ServiceThrottle.MaxConcurrentSessions, que de
forma predeterminada restringe el número de conexiones de canal con sesión simultáneas a 10.(A
diferencia de las cuotas, si se alcanza este valor de acelerador, la aplicación continúa con el
procesamiento pero no acepta nuevos canales con sesión, lo que significa que los nuevos clientes no se
pueden conectar hasta que uno de los otros canales con sesión haya finalizado.)

Estos controles están diseñados para proporcionar una mitigación rápida contra ciertos tipos de ataques
o para mejorar métrica de rendimiento tal como el consumo de memoria, el tiempo de inicio, etc.Sin
embargo, dependiendo de la aplicación, estos controles pueden impedir el rendimiento de la aplicación
del servicio o evitar que la aplicación funcione.Por ejemplo, una aplicación diseñada para transmitir
secuencias de vídeo puede superar con facilidad la propiedad
TransportBindingElement.MaxReceivedMessageSize predeterminada.En este tema se proporciona un
resumen de los diferentes controles aplicados a las aplicaciones en todos los niveles de WCF, describe
varias maneras para obtener más información sobre si un valor está entorpeciendo su aplicación, y
describe maneras de corregir varios problemas.La mayoría de los aceleradores y algunas cuotas están
disponibles en el nivel de aplicación, incluso cuando la propiedad base es una serialización o una
restricción de transporte.Por ejemplo, puede establecer la propiedad
DataContractSerializer.MaxItemsInObjectGraph utilizando la propiedad
ServiceBehaviorAttribute.MaxItemsInObjectGraph en la clase de servicio.

Nota
Si tiene un problema determinado, debería leer primero Inicio rápido de solución de problemas de
WCF para ver si su problema (y una solución) aparecen en la lista.

Las propiedades que restringen los procesos de serialización están listadas en Consideraciones de
seguridad para datos.Las propiedades que restringen el consumo de recursos relacionadas con
transportes están listadas en Cuotas de transporte.Las propiedades que restringen el consumo de
recursos en el nivel de aplicación son los miembros de la clase ServiceThrottle.

Detectar la aplicación y los problemas de rendimiento


relacionados con los valores de cuota
Los valores predeterminados de los valores anteriores se han elegido para habilitar la funcionalidad de
la aplicación básica en una amplia gama de tipos de aplicación proporcionando al mismo tiempo
protección básica contra los problemas de seguridad comunes.Sin embargo, los diseños de las
diferentes aplicaciones pueden superar uno o más valores de acelerador aunque por otro lado la
aplicación sea segura y funcione como se ha diseñado.En estos casos, debe identificar qué valores de
acelerador se superan y en qué nivel, y decidir la acción adecuada para aumentar el rendimiento de la
aplicación.

Normalmente, al escribir la aplicación y depurarla, establece la propiedad


ServiceDebugBehavior.IncludeExceptionDetailInFaults en true en el archivo de configuración o
mediante programación.Esto indica WCF que se devuelvan marcas de traza de la pila de excepción de
servicio a la aplicación cliente para analizarlas.Esta característica crea informes de la mayoría de las
excepciones en el nivel de aplicación de manera que se muestran qué valores de cuota podrían estar
implicados, si ése es el problema.

En tiempo de ejecución se producen algunas excepciones bajo el nivel de aplicación visible y no se


devuelven por medio de este mecanismo ni pueden controlarse mediante una implementación
System.ServiceModel.Dispatcher.IErrorHandler personalizada.Si está en un entorno de desarrollo
como Microsoft Visual Studio, la mayoría de estas excepciones se muestran automáticamente.Sin
embargo, algunas excepciones pueden ser enmascaradas por algunos valores del entorno de desarrollo
como los valores Just My Code en Visual Studio 2005.

Independientemente de las funciones de su entorno de desarrollo, puede utilizar las funciones de traza
de WCF y registro de mensajes para depurar todas las excepciones y ajustar el rendimiento de sus
aplicaciones.Para obtener más información, vea Uso del seguimiento para solucionar problemas de su
aplicación.
Problemas de rendimiento y XmlSerializer
Los servicios y las aplicaciones cliente que usan tipos de datos que son serializables mediante
XmlSerializer generan y compilan el código de serialización de los tipos de datos en tiempo de
ejecución, lo que se puede traducir en un rendimiento de inicio lento.

Nota
El código de serialización generado previamente solo puede usarse en aplicaciones cliente, no en
servicios.

Herramienta de utilidad de metadatos de ServiceModel (Svcutil.exe) puede mejorar el rendimiento de


inicio de estas aplicaciones generando el código de serialización necesario a partir de los ensamblados
compilados para la aplicación.Para obtener más información, vea Cómo: Mejorar el tiempo de inicio de
las aplicaciones cliente WCF mediante XmlSerializer.

Problemas de rendimiento al hospedar los servicios WCF bajo


ASP.NET
Cuando un servicio WCF se hospeda bajo IIS y ASP.NET, la configuración de IIS y ASP.NET puede
afectar al rendimiento y al consumo de memoria del servicio WCF.Para obtener más información sobre
el rendimiento de ASP.NET, vea Mejorar el rendimiento de ASP.NET.Una configuración que quizá
pueda tener consecuencias imprevistas es la propiedad MinWorkerThreads, que es una propiedad de la
clase ProcessModelSection.Si la aplicación tiene un número fijo o pequeño de clientes, al establecer
MinWorkerThreads en 2 se podría observar un aumento del rendimiento en un equipo con varios
procesadores que tenga un uso de CPU próximo al 100%.Esta mejora del rendimiento tiene su precio:
aumentará también el consumo de memoria, lo que podría disminuir la escalabilidad.

Ver también
Administración y diagnóstico
Datos de gran tamaño y secuencias
Mejorar el rendimiento de la recolección de
elementos no utilizados
2017-2-8 9 minutos para leer

[ Actualizado para aplicaciones para UWP en Windows 10. Para leer más artículos sobre Windows 8.x,
consulta el archivo ]

La memoria de las aplicaciones para la Plataforma universal de Windows (UWP) escritas en C# y


Visual Basic se administra de manera automática con el recolector de elementos no utilizados de .NET.
En esta sección se resume el comportamiento y los procesos recomendados de rendimiento del
recolector de elementos no usados de .NET para las aplicaciones para UWP. Para más información
sobre el funcionamiento del recolector de elementos no utilizados de .NET y las herramientas para
depurar y analizar su rendimiento, consulta Recolección de elementos no utilizados.

Nota La necesidad de intervenir en el comportamiento predeterminado del recolector de elementos no


usados es una clara señal de problemas de memoria generales en la aplicación. Para más información,
consulta Herramienta de uso de memoria durante la depuración en Visual Studio2015. Este tema solo
se aplica a C# y Visual Basic.

El recolector de elementos no utilizados determina cuándo ejecutarse buscando un equilibrio entre el


consumo de memoria del montón administrado y cantidad de trabajo que debe realizar la recolección
de elementos no utilizados. Uno de los modos en que el recolector de elementos no utilizados hace esto
es dividiendo el montón en generaciones y recolectando solo parte del montón la mayor parte del
tiempo. Hay tres generaciones en el montón administrado:

 Generación 0. Esta generación contiene los objetos asignados recientemente, a menos que su tamaño
sea de 85KB o superior, en cuyo caso forman parte del montón de objetos grandes. El montón de
objetos grandes se recolecta con las recolecciones de generación 2. Las recolecciones de generación 0
son el tipo de recolección más frecuente y limpian los objetos de corta duración, como las variables
locales.
 Generación 1. Esta generación contiene objetos que han sobrevivido a las recolecciones de generación
0. Sirve como búfer entre las generaciones 0 y 2. Las recolecciones de generación 1 tienen lugar con
menor frecuencia que las de generación 0 y limpian los objetos temporales que se encontraban activos
durante las recolecciones de generación 0 anteriores. Las recolecciones de generación 1 también
recolectan la generación 0.
 Generación 2. Esta generación contiene los objetos de larga duración que han sobrevivido a las
recolecciones de las generaciones 0 y 1. Las colecciones de generación 2 son las menos frecuentes y
recolectan todo el montón administrado, incluido el montón de objetos de gran tamaño que contiene
objetos cuyo tamaño es de 85KB o superior.

Puedes medir el rendimiento del recolector de elementos no usados en relación con dos aspectos: el
tiempo que tarda la recolección de elementos no usados y el consumo de memoria del montón
administrado. Si tienes una aplicación pequeña con un tamaño de montón inferior a 100MB, céntrate en
reducir el consumo de memoria. Si tienes una aplicación con un montón administrado superior a
100MB, céntrate solo en reducir el tiempo de la recolección de elementos no usados. A continuación se
muestra cómo mejorar el rendimiento del recolector de elementos no usados de .NET.
Reducir el consumo de memoria
Liberar las referencias

Si un objeto de tu aplicación tiene una referencia, dicho objeto y todos los objetos a los que hace
referencia no pueden recolectarse. El compilador de .NET realiza un buen trabajo al detectar cuándo
una variable ya no se usa. De este modo, los objetos que contienen esa variable se habilitarán para la
recolección. Pero, en algunos casos, es posible que no sea evidente que algunos objetos tienen una
referencia a otros objetos, porque parte del gráfico de objeto puede pertenecer a bibliotecas que usa tu
aplicación. Para conocer las herramientas y las técnicas que te permiten averiguar qué objetos
sobreviven a una recolección de elementos no usados, consulta Recolección de elementos no usados y
rendimiento.

Inducir una recolección de elementos no utilizados si es útil

Induce una recolección de elementos no utilizados solamente si has medido el rendimiento de tu


aplicación y si has determinado que esto lo mejorará.

Para inducir una recolección de elementos no usados de una generación, llama a GC.Collect(n), donde
n es la generación que quieres recolectar (0, 1 o 2).

Nota Se recomienda no forzar una recolección de elementos no usados en la aplicación, ya que el


recolector de elementos no usados usa muchas medidas heurísticas para determinar el mejor momento
de realizar una recolección y, si la fuerzas, en muchos casos provocarás un uso innecesario de la CPU.
Pero si sabes que tienes una gran cantidad de objetos en la aplicación que ya no se usan y quieres
devolver esta memoria al sistema, puede resultar conveniente forzar una recolección de elementos no
utilizados. Por ejemplo, puedes inducir una recolección al final de una secuencia de carga en un juego
para liberar memoria antes de comenzar la partida.

Para evitar inducir accidentalmente demasiadas recolecciones de elementos no utilizados, puedes


establecer el valor de GCCollectionMode en Optimized. Esto indica al recolector de elementos no
utilizados que debe iniciar una recolección solo si determina que será lo suficientemente productiva
como para justificar su ejecución.

Reducir el tiempo de recolección de elementos no utilizados


Esta sección se aplica si has analizado tu aplicación y has observado que tarda mucho en recolectar los
elementos no usados. El tiempo de pausa relacionado con la recolección de elementos no usados
abarca: el tiempo que se tarda en ejecutar una sola fase de recolección de elementos no usado y el
tiempo total que tarda la aplicación en realizar las recolecciones de elementos no usados. El tiempo que
se tarda en realizar una recolección depende de la cantidad de datos activos que debe analizar el
recolector. El tamaño de las generaciones 0 y 1 es limitado, pero la generación 2 crece a medida que se
activan objetos de larga duración en la aplicación. Esto significa que el tiempo de recolección para las
generaciones 0 y 1 son limitados, mientras que las recolecciones de generación 2 pueden tardar más
tiempo. La frecuencia con la que se ejecutan las recolecciones de elementos no usados depende
principalmente de la cantidad de memoria que se asigna, porque la recolección de elementos no usados
libera memoria para cumplir con las solicitudes de asignación.
En ocasiones, el recolector de elementos no utilizados pausa la aplicación para llevar a cabo el trabajo,
pero no necesariamente la pausa todo el tiempo que tarda en realizar la recolección. Los tiempos de
pausa no suelen ser perceptibles para el usuario en la aplicación, especialmente en las recolecciones de
las generaciones 0 y 1. La característica de recolección de elementos no utilizados en segundo plano
del recolector de elementos no utilizados de .NET permite que las recolecciones de generación 2 se
realicen al mismo tiempo que se ejecuta la aplicación y, de este modo, la aplicación solo se pausa por
períodos cortos. Pero no siempre es posible realizar una recolección de generación 2 como una
recolección en segundo plano. En ese caso, el usuario puede percibir la pausa si tienes un montón
demasiado grande (más de 100 MB).

Las recolecciones de elementos no usados frecuentes pueden contribuir a un mayor consumo de CPU
(y, por lo tanto, de energía), tiempos de carga más prolongados o una menor velocidad de fotogramas
en la aplicación. A continuación se ofrecen algunas técnicas que puedes usar para reducir el tiempo de
recolección de elementos no usados y las pausas relacionadas con la recolección en tu aplicación para
UWP.

Reducir las asignaciones de memoria

Si no asignas ningún objeto, el recolector de elementos no utilizados no se ejecutará a menos que se


detecte una situación de memoria insuficiente en el sistema. La reducción de la cantidad de memoria
asignada se traduce directamente en recolecciones de elementos no utilizados menos frecuentes.

Si en algunas secciones de tu aplicación no quieres que haya ningún tipo de pausa, puedes preasignar
los objetos necesarios con antelación durante un momento en que el rendimiento no sea tan importante.
Por ejemplo, un juego podría asignar todos los objetos necesarios para la partida durante la pantalla de
carga de un nivel en lugar de realizar las asignaciones durante la partida propiamente dicha. Esto evita
pausas mientras el usuario está jugando y da como resultado una velocidad de fotogramas más alta y
coherente.

Reducir recolecciones de generación 2 al evitar objetos de mediana duración

Las recolecciones de elementos no utilizados generacionales se realizan más eficazmente cuando la


aplicación cuenta con objetos cuya duración es realmente corta o realmente larga. Los objetos de corta
duración se recolectan en las recolecciones de las generaciones 0 y 1, que consumen menos recursos, y
los objetos de larga duración se promueven a la generación 2, que se recolecta con menor frecuencia.
Los objetos de larga duración son los que se usan durante todo el ciclo de vida de la aplicación, o
durante una período significativo, por ejemplo, durante una página o nivel de juego específicos.

Si con frecuencia creas objetos que tienen una duración temporal, pero duran lo suficiente como para
avanzar a la generación 2, se producirán más recolecciones de generación 2, las cuales consumen más
recursos. Es posible que puedas reducir el tiempo de las recolecciones de generación 2 si reciclas los
objetos existentes o si los eliminas con mayor rapidez.

Un ejemplo común de objetos de mediana duración son los objetos que se usan para mostrar elementos
en una lista por la que se desplaza un usuario. Si se crean objetos cuando aparecen los elementos de la
lista y se deja de hacer referencia a ellos tan pronto como se desplazan fuera de la vista, tu aplicación
tendrá una gran cantidad de recolecciones de generación 2. En este tipo de situaciones, puedes
preasignar un conjunto de objetos y reutilizarlos para los datos que se muestran al usuario de manera
activa y usar objetos de corta duración para cargar la información a medida que aparecen los elementos
de la lista.

Reducir recolecciones de generación 2 al evitar objetos de gran tamaño con duraciones cortas

Los objetos de 85KB o mayores se asignan al montón de objetos grandes (LOH) y se recolectan como
parte de la generación 2. Si tienes variables temporales como, por ejemplo, búferes, cuyo tamaño
supera los 85KB, una recolección de generación 2 las eliminará. Al limitar las variables temporales a
menos de 85KB, se reduce el número de recolecciones de generación 2 en la aplicación. Una técnica
común consiste en crear una grupo de búferes y volver a usar los objetos del grupo para evitar
asignaciones temporales de gran tamaño.

Evitar objetos con muchas referencias

El recolector de elementos no utilizados sigue las referencias entre los objetos desde las raíces de la
aplicación para determinar qué objetos están activos. Para más información, consulta el tema que
explica lo que sucede durante una recolección de elementos no utilizados. Si un objeto contiene muchas
referencias, el recolector de elementos no utilizados deberá realizar una mayor cantidad de trabajo. Una
técnica común (especialmente con los objetos grandes) consiste en convertir los objetos con muchas
referencias en objetos sin referencias (por ejemplo, en lugar de almacenar una referencia, almacena un
índice). Obviamente, esta técnica solo funciona cuando es posible hacerlo de forma lógica.

El reemplazo de referencias de objeto por índices puede implicar una modificación complicada y
perjudicial en la aplicación, y es más eficaz en objetos grandes con una gran cantidad de referencias.
Hazlo solamente si notas tiempos de recolección de elementos no utilizados prolongados en la
aplicación relacionados con objetos con muchas referencias.
Liberar memoria ram de aplicación en visual basic.net
Hace tiempo estuve en contacto con el colega @Cristian. Tuvimos una platica muy apasionada sobre
el mundo de Visual Basic .Net y de un momento a otro me comentó que había encontrado un código
que me llamaría la atención.

Él inicio con una pregunta: ¿Qué sucede después de que una aplicación entra en un proceso muy
pesado?. Mi respuesta (después de analizar por un rato la pregunta) fue: Es probable que la
aplicación se quede consumiendo mucha memoria RAM. Y sí, coincidimos los 2 en esa parte.

El código que había encontrado @Cristian ayuda a que se liberen recursos que la aplicación ya no
utiliza, ya que obliga a que entre de inmediato el Garbage Collector.

A continuación les comparto el código:

Public Class FreeMemory

Private Declare Function SetProcessWorkingSetSize Lib "kernel32.dll" ( _


ByVal process As IntPtr, _
ByVal minimumWorkingSetSize As Integer, _
ByVal maximumWorkingSetSize As Integer) As Integer

Public Shared Sub FlushMemory()


Try
GC.Collect()
GC.WaitForPendingFinalizers()
If (Environment.OSVersion.Platform = PlatformID.Win32NT) Then
SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, -1, -1)
End If
Catch ex As Exception

End Try
End Sub

End Class

view raw LiberarMemoriaRAM.vb hosted with ❤ by GitHub

En lo personal lo empecé a implementar después de procesos “rudos” (después de generar un reporte,


después de recorrer ciertos documentos, etc) y noté un gran cambio en el consumo de memoria RAM
de la aplicación.

Para más información, puedes consultar el artículo Garbage Collection en MSDN

También podría gustarte