2010-12-07 14 views
6

Tengo una aplicación .Net Framework # 4.0 que realiza una gran cantidad de solicitudes web utilizando las clases WebRequest/WebResponse, ya que veo que tiene pérdida de memoria (o tal vez estoy haciendo algo mal) I escribió una pequeña aplicación sencilla que demuestra esto:WebRequest/WebResponse Memory leak

class Program 
{ 

    public static void Main(string[] args) 
    { 
     while(true) 
     { 
      var webRequest = (HttpWebRequest)WebRequest.Create("http://www.gooogle.com"); 
      Init(webRequest); 
      using (var webResponse = (HttpWebResponse)webRequest.GetResponse()) 
      { 
       var responseStream = webResponse.GetResponseStream(); 

       responseStream.ReadTimeout = 30; 
       var streamReader = new StreamReader(responseStream, Encoding.UTF8); 
       var page = streamReader.ReadToEnd(); 

       streamReader.Close(); 
       streamReader.Dispose(); 

       responseStream.Close(); 
       responseStream.Dispose(); 

       webResponse.Close(); 

       Console.WriteLine("Done"); 

       //GC.Collect(); 
      } 
     } 
    } 

    private static void Init (HttpWebRequest webRequest) 
    { 
     webRequest.Method = "GET"; 
     webRequest.Host = "www.gooogle.com"; 
     webRequest.UserAgent = 
      "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; GTB6.5; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; OfficeLiveConnector.1.4; OfficeLivePatch.1.3; .NET4.0C; .NET4.0E; InfoPath.3) chromeframe/5.0.375.62"; 
     webRequest.Accept = 
      "application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*"; 
     webRequest.KeepAlive = true; 
    } 
} 

la única solución que subí es el uso GC.Collect() (sin marcar en el ejemplo), todos los objetos están dispuestos, todos los flujos están cerradas, soy yo Echando de menos algo ?

Encontré algo pero no entiendo el motivo, si minimizo la consola, el uso de memoria disminuye y se ve O.K, ¿cuál puede ser la razón de que haya un problema con Conosole o WinForm, cómo puedo solucionarlo?

+2

¿Cómo ve que tiene una pérdida de memoria? –

+3

Stream y StreamReader también implementan IDisposable. –

+3

si GC.Collect() corrige su fuga, no es realmente una fuga. Es totalmente normal que el GC cuelgue a los recursos si no hay necesidad de liberarlos. ¿Ve las implicaciones de rendimiento cuando ejecuta su aplicación por un largo tiempo? ¿Algo no funciona como se esperaba debido al aumento en el uso de la memoria? ¿Perfilaron el uso de la memoria a lo largo del tiempo durante un período prolongado? – BrokenGlass

Respuesta

1

Prueba esto:

while (true) 
{ 
    var webRequest = (HttpWebRequest) WebRequest.Create("http://www.gooogle.com"); 
    Init(webRequest); 
    using (var webResponse = (HttpWebResponse) webRequest.GetResponse()) 
    { 
     using (var responseStream = webResponse.GetResponseStream()) 
     { 
      responseStream.ReadTimeout = 30; 
      using (var streamReader = new StreamReader(responseStream, Encoding.UTF8)) 
      { 
       var page = streamReader.ReadToEnd(); 
      } 
     } 

     Console.WriteLine("Done"); 
    } 
} 
+0

"usar" es lo mismo que deshacerse manualmente del recurso que hice (por lo que no veo cómo lo ayudará), pero de todos modos hice la prueba, el resultado es el mismo .( – Robob

+1

"usar" no es lo mismo cuando se produce una excepción. –

+0

@JohnSaunders, entonces, ¿qué cambiarías en el código para manejar la excepción también? Gracias ... –

0

Sí, encontramos una fuga también. La solución es ... ten cuidado con lo que haces con esto. Considera no usarlo. Creo que tiene ... problemas (al menos en 3.5, presumiblemente en otras versiones también). Ah, y no olvide informarlo/votar en Microsoft Connect.

+0

Acabo de realizar la prueba y no puedo detectar la pérdida de memoria. la memoria creció durante 5MB durante 1min y luego se detiene. Así que supongo que no hay pérdida de memoria. –

+0

¿Ha intentado crear muchos de ellos en diferentes subprocesos? – Tom

+0

Acabo de probar una aplicación de muestra con 5 subprocesos y en este caso ha aumentado la memoria de toda la aplicación de 12 MB durante los primeros 1-2 minutos y después de eso ha estado funcionando durante ~ 3min sin ningún cambio en la cantidad de memoria. Después de agregar 'GC.Collect()' a la rutina de subprocesos, consume menos memoria. Así que todas mis pruebas me dieron un comportamiento similar: la aplicación aumenta su memoria para una cantidad constante y no tuvo un crecimiento permanente en la memoria. ¿Pero podría ser que mis pruebas difieran de las tuyas? –

4

Está asignando memoria en un circuito cerrado. Probablemente no tenga una pérdida de memoria, tenga una aplicación de mal comportamiento (en el sentido de que está usando muchos recursos del sistema sin ningún motivo)

El recolector de basura no va a interrumpir su ciclo para memoria liberada compacta a menos que tenga que hacerlo debido a la presión de la memoria. La solución simple sería introducir un retraso entre las iteraciones del ciclo (podría ser tan simple como Thread.Sleep, aunque no lo recomiendo).

Una vez que el programa no funciona, es tan difícil consumir toda la CPU disponible el tiempo debería permitir que el GC se ejecute con más frecuencia.

+0

No es un ciclo cerrado, ya que readtoend es un método de bloqueo. – Tom

+0

@Tom En realidad, es correcto, pero por el motivo equivocado. No es un bucle estrecho porque el método GetResponse invoca un [espera IOCP] (http://stackoverflow.com/questions/3232637/scaling-up-multiple-httpwebrequests/3327671#3327671) que libera el proceso para hacer otros trabajos (como la recolección de basura.) – hemp

+0

bien ... ¿pero no se lee de la misma manera? – Tom