2010-08-04 25 views
16

Tengo un sitio web ASP.NET que afectará aproximadamente a 2 gb de memoria física utilizada dentro de unos 3-4 días, lo que para mí suena realmente mal. Por el momento, configuré IIS para reiniciar el proceso del grupo de aplicaciones cuando alcanza los 500mb. Me gustaría intentar localizar el problema.ASP.NET Sitio web Memoria Uso bastante alto

Al crear una nueva instancia de un objeto en .NET, que estaba bajo la impresión de que no necesita ser liberado como el recolector de basura .NET lo hará por mí.

¿Es ese el caso o podría ser esta una de las razones por las que tengo problemas?

+0

¿Qué ha configurado el servidor para su parámetro de tiempo de espera de la sesión? –

+0

He echado un vistazo y puedo ver que la sesión de mi sitio web está configurada como En proceso y hay un tiempo de espera contra la cookie asp, pero no puedo encontrar una específicamente para las sesiones. ¿Puedes aconsejar? – webnoob

+0

Esta es la línea en mi archivo web.config para sesiones: - Parece que está configurado en 20 minutos. – webnoob

Respuesta

15

.NET administrará la recolección de basura para usted de manera muy eficiente. Mientras que en los tipos que implementan IDisposable es aconsejable llamar al método Dispose, probablemente este no sea su problema. Las pérdidas de memoria pueden ocurrir en .NET por muchas razones. Éstos son algunos:

  • Caché demasiados datos por usuario en la sesión.
  • Caché demasiados datos en un nivel de aplicación en la memoria caché de la aplicación o en una variable estática, como un diccionario.
  • Almacena controles web (o controles de usuario) en la sesión o el nivel de aplicación.
  • Enlaza instancias a eventos en tipos estáticos o a tipos que siguen siendo referenciados (porque están almacenados en un caché).

Espero que esto le dé algunas ideas sobre dónde buscar.

ACTUALIZACIÓN: Usted debe ver this video sobre la depuración ASP.NET.

ACTUALIZACIÓN 2: Acerca de su comentario en mi respuesta el siguiente. El CLR recogerá toda la memoria administrada, por lo tanto, todos los objetos que cree usando new se recopilarán. En este sentido, no importa si un objeto implementa IDisposable o no. Sin embargo, hay muchas veces que necesita usar recursos nativos (como manejadores de archivos, identificadores gráficos, conexiones de bases de datos, uso de memoria nativa -thus no administrada) directa o indirectamente. CLR no sabe cómo liberar estos recursos. Para esto .NET tiene la noción de finalizadores. Un finalizador es un método virtual que puede implementar un desarrollador de una clase. Cuando hace esto, el CLR llamará a este método después de que una instancia de ese tipo no se refiera y antes de que se recopile. Los finalizadores suelen contener lógica que libera estos recursos. En otras palabras, cuando un tipo necesita recursos nativos, generalmente tendrá un método de finalizador que permita que el tipo libere esos recursos.

¿Qué pasa con el CLR se refiere, la historia termina aquí. El CLR no tiene un manejo específico de los objetos que implementan la interfaz IDisposable. Sin embargo, el recolector de basura .NET es de naturaleza no determinista. Esto significa que no sabe cuándo se ejecuta y si se ejecuta. Esto significa que puede tomar mucho tiempo antes de que sus recursos nativos se limpien (porque un finalizador solo se llamará después de un recopilatorio). Sin embargo, para muchos recursos, es necesario liberarlos tan pronto como haya terminado con ellos. Por ejemplo, tiende a quedarse sin conexiones de bases de datos rápidamente cuando no las cierra o cuando está trabajando con GDI + en .NET a través del espacio de nombres System.Drawing).

Por esta razón se introdujo la interfaz IDisposable. Una vez más, el CLR y el recolector de basura no miran esta interfaz. Es un contrato entre el tipo y sus usuarios, lo que permite a los usuarios liberar directamente los recursos subyacentes de un objeto. En un diseño normal, tanto el finalizador del objeto como el método Dispose del objeto invocarán el mismo método privado o protegido que liberará esos recursos. Cuando un tipo implementa IDisposable es aconsejable llamar es Dispose método cuando haya terminado con él o envuelva el objeto en un comunicado using para permitir la liberación de los recursos nativos a ser determinista.

Así que volver a su pregunta. Todos los objetos gestionados serán recopilados por el GC, pero los recursos nativos no lo harán. Por lo tanto, los tipos pueden implementar un método de finalizador y esos objetos también implementarán típicamente la interfaz IDisposable. Llamar al Dispose en ellos liberará explícita y directamente esos recursos nativos.

Espero que esto tenga sentido.

+0

¿Esto significa que solo las clases heredadas de IDisposable serán GC'd? – webnoob

+0

@Webnoob: mira mi actualización. – Steven

+0

Creo que es posible que haya encontrado la causa de mi problema :) Todas las imágenes en mi sitio web se ejecutan a través de un controlador personalizado que he escrito que crea una miniatura de esa imagen. Por lo que puedo recordar, no estoy haciendo nada para limpiar ese código y definitivamente usa los métodos de system.drawing. Un gran lugar para comenzar para mí. Gracias por la publicacion. Marqué esta como respuesta ya que me da la mayor información que necesito en este momento. – webnoob

6

Su uso de memoria puede tener muchas razones, pero Garbage Collection en .NET es muy preciso. Es decir, hace mucho por ti, pero a veces no tanto como cabría esperar.

En concreto, sólo se puede limpiar objetos para los que no existen referencias activas, por lo que si le hacen con una clase, pero algo todavía tiene una referencia a él, tendrá que eliminar esa referencia, de manera que el GC puede recuperar esa memoria por ti. Además, si tiene conexiones abiertas inactivas (por ejemplo, a un DB o algo así), no olvide cerrarlas y desecharlas. Por lo general, nos envuelva tales objetos en using bloques de la siguiente manera:

using(SqlConnection conn = new SqlConnection(myConnString)) 
{ ...rest of code here } 

Esto se cerrarán automáticamente y disponer de la conexión; Estoy bastante seguro de que también te puede probar/finalmente gratis (alguien me revisa eso, por favor).

Aparte de eso, la respuesta es "el perfil, el perfil, el perfil" hasta que encuentre su fuga/cuello de botella/lo que sea.

+1

+1 para perfil perfil perfil –

+1

Sí, usar la instrucción 'using' es equivalente a usar un bloque' try'-'finally' con una llamada a 'Dispose' en el bloque' finally'. – Steven

+0

@Steven: gracias por eso. – AllenG

0

Si bien es cierto que no tiene que liberar explícitamente la memoria y el recolector de basura lo hará por usted, es posible que el código inadvertidamente mantenga una referencia a un objeto para evitar que se recopile: esto es esencialmente un pérdida de memoria.

En ASP.NET los objetos permanecen "vivos" mientras están referenciados por la aplicación y la memoria caché de sesión. Sin saber nada sobre su aplicación, le sugiero que obtenga un perfilador de memoria y mire más de cerca lo que está en la memoria y si la aplicación o el caché de sesión se mantiene en algo que no debería.

1

Las pérdidas de memoria en .NET todavía son posibles. Es cierto que, en general, no es necesario liberar objetos (hay algunas excepciones, como el objeto Graphics), pero si mantiene referencias a ellos, no obtendrán basura recolectada, ya que todavía se referencian.

Si el GC ve que un objeto se está haciendo referencia en alguna parte de su aplicación, no va a destrozarlo.

Control hacia fuera este artículo sobre Code Project pérdidas de memoria .NET y cómo ir sobre la localización y fijación de ellos.

2

Hay algunas cosas que debe buscar en:

En primer lugar, ¿está utilizando sesiones? ¿Están en sesiones de proceso o SQL? Si están en proceso, ¿en qué tiempo está establecido? Si tiene un tiempo de espera muy largo, esto podría explicar por qué está usando tanta memoria (las sesiones de los usuarios se almacenarían durante un tiempo prolongado).

En segundo lugar, la eliminación de objetos. Los .NET garbage collector eliminará las referencias para usted, pero cuando cree objetos que implementen la interfaz IDisposable, siempre debe usar la palabra clave using.

using(Foo foo = new Foo()) 
{ 
    ... 
} 

es el equivalente de hacer:

Foo foo; 
try 
{ 
    foo = new Foo(); 
    ... 
} 
finally 
{ 
    foo.Dispose(); 
} 

y asegurará que se deshaga de sus objetos de manera eficiente.

Si todavía no puede encontrar nada obvio en su código, puede crear un perfil, comenzando con los métodos que se llaman más. Puede encontrar información sobre buenos perfiladores here. Eso definitivamente lo llevará a la fuente de su problema.

1

Si su aplicación ASP.NET utiliza eventos (y cuál no), then you have to make sure you unsubscribe from the event.

Regla de oro:

Si utiliza += suscribirse a un evento, entonces es necesario utilizar -= en el método Dispose() para darse de baja.

Hay lotsofresourceson this topic, y he tenido un poco de dolor en aplicaciones He trabajado en su programador porque run-of-the-mill no se da cuenta que los eventos pueden causar pérdidas de memoria.

+0

En la mayoría de los casos, cancelar la suscripción es innecesario. Solo es necesario si te suscribes a un evento en un objeto de larga vida. Los eventos entre objetos de corta vida como los controles en una sola página no necesitan limpieza manual: http: // stackoverflow.com/questions/345130/do-i-need-to-unsubscribe-from-manualmente-suscrito-a-eventos-en-asp-net –

1

Utilice un memory profiler (ya sea en un volcado de memoria o en su entorno real) cuando su memoria excede los 500 MB para obtener una pista sobre qué objetos ocupan todo ese espacio.

Al perfilar en su entorno de desarrollo, es posible que vea un tipo de objeto particular que solo crece cuando navega por su sitio, mientras que otros permanecen globalmente iguales.