2011-05-27 21 views
7

Tengo una aplicación .NET que necesita un WebBrowser para navegar automáticamente por un grupo de páginas. Pero si voy a, por ejemplo, Google y configuro Google Instant, y luego busco algo y navego manualmente a través del siguiente botón varias veces, la memoria utilizada por mi aplicación comenzará a aumentar.Problema de memoria WebBrowser

El problema podría ser que Google Instant está de alguna manera manteniendo los datos de las páginas anteriores, pero incluso después de navegar en otro lugar, como "sobre: ​​en blanco", la memoria utilizada no disminuirá. Este problema también se produce con IE 9. empecé a escribir por mi memoria utilizada en la página 60 y esto es lo que tengo (con IE 9):

Page 60: 180 MB 
Page 70: 214 MB 
Page 80: 245 MB 
Page 90: 280 MB 

Así como se puede ver, la memoria aumenta casi linealmente en un 30 - 35 MB cada 10 páginas. Esto no sería un problema si la memoria se liberaría después de navegar fuera de Google. Pero no es.

También probé this y no hice nada.

Editar: Hice un proyecto solo para probar esto. Aquí está mi Form1 código:

namespace WebBrowserMemoryTest 
{ 
    public partial class Form1 : Form 
    { 
     private int _Pages; 

     public Form1() 
     { 
      InitializeComponent(); 
      webBrowser1.Navigate("http://www.google.com"); 
     } 

     private void startButton_Click(object sender, EventArgs e) 
     { 
      _Pages = 0; 
      timer1.Start(); 
     } 

     private void stopButton_Click(object sender, EventArgs e) 
     { 
      timer1.Stop(); 
     } 

     private void timer1_Tick(object sender, EventArgs e) 
     { 
      HtmlElement next = webBrowser1.Document.GetElementById("pnnext"); 

      if (_Pages <= 90) 
      { 
       if (null != next) 
       { 
        string href = next.GetAttribute("href"); 
        webBrowser1.Navigate(href); 
        _Pages++; 
       } 
       else 
       { 
        timer1.Stop(); 
        MessageBox.Show("Next button not found"); 
       } 
      } 
      else 
      { 
       timer1.Stop(); 
       MessageBox.Show("Done"); 
      } 
     } 

     private void goButton_Click(object sender, EventArgs e) 
     { 
      webBrowser1.Navigate(textBox1.Text); 
     } 

     private void freeMemButton_Click(object sender, EventArgs e) 
     { 
      MemoryManagement.FlushMemory(); 
     } 
    } 

    public class MemoryManagement 
    { 
     [DllImport("kernel32.dll")] 
     public static extern bool SetProcessWorkingSetSize(IntPtr proc, int min, int max); 

     public static void FlushMemory() 
     { 
      GC.Collect(); 
      GC.WaitForPendingFinalizers(); 
      if (Environment.OSVersion.Platform == PlatformID.Win32NT) 
      { 
       SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1); 
      } 
     } 
    } 
} 

Lo que hago es buscar cualquier cosa en Google con Google Instant convertido en , y luego presione el startButton (que invoca startButton_Click). Después de aproximadamente 80 páginas presiono stopButton, luego navego a "about: blank", luego regreso a Google y busco cualquier otra cosa y presiono startButton nuevamente.

Lo probé por primera vez en mi PC, que tiene 6 GB de ram. Cuando llegué a 1,5 GB, la aplicación dejó de responder, pero no obtuve ninguna excepción OutOfMemory. Luego lo probé en una máquina virtual con Windows 7 y 1 GB RAM. Cuando llegó a unos 300 MB, el navegador web de mi aplicación dejó de responder.

Si presiono el botón freeMem, que llama al freeMemButton_Click, la memoria vuelve a bajar (pero vea mi Edit2). Entonces eso "resuelve" mi problema. Pero ahora mi pregunta es ¿por qué tengo que llamar al SetProcessWorkingSetSize? ¿No se supone que Windows liberará la memoria automáticamente? Además, no estoy seguro si llamar a esa función tendrá algún efecto secundario.

Estoy bastante seguro de que esto es un error. ¿Debo seguir adelante y reportarlo?

Edit2: Probé la solución de Stefan (llamando al SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1)) y no lo solucioné. La memoria cayó en el administrador de tareas, pero esto es solo aparente. La aplicación dejó de responder después de tantas navegaciones de navegador que dejó de responder cuando no llamaba a esa función.

+0

¿Estás hacer ningún tipo de controlador de eventos en el navegador web? –

+0

No. Solo el código que ves – Juan

+0

¿Alguna actualización sobre esto? – atwellpub

Respuesta

3

Windows realmente no devuelve memoria liberada si no hay razón para ello. Y la única razón sería si otra aplicación requiere esa memoria y ya no hay otra memoria disponible. Es por eso que parece que el uso de la memoria aumenta.

intentar llamar

SetProcessWorkingSetSize (GetCurrentProcess(), -1, -1);

a veces - esto obligará al sistema operativo a devolver toda la memoria liberada al sistema operativo.

+0

¿Es normal alcanzar 1,5 GB sin que Windows libere la memoria? – Juan

+0

Por favor, mira mi edición. – Juan

+0

Ejecuto una prueba. Eso no lo arregla. La memoria parece liberarse en el Administrador de tareas, pero la aplicación deja de responder después de la misma cantidad de navegaciones del navegador que lleva a dejar de responder cuando no llama a esa función. – Juan

0

creo HTMLElement pnext no se libera, ya que es ComObject, y puede haber un error en el control del explorador.

Trate pnext.Release o tratar Marshal.Release y obtener la instancia de ComObject a liberar.

+0

acaba de intentar añadir el 'Si (null = siguiente!) Marshal.ReleaseComObject (next.DomElement);' línea al final de mi método 'timer1_Tick' pero no hacer una diferencia. Alcanzado 1 GB. – Juan

+0

Intente llamar a MemoryManagement.FlushMemory antes de navegar –

+0

. También lo intenté. No funciona (ver mi última edición). – Juan

0

al trabajar con Webbrowser, encontré que es importante esperar el evento "documentcompleted" y verificar si el "estado" está "completo" antes de navegar en la página siguiente. Otra cosa cancelar la navegación y esperar de nuevo para el estado de documento-completado (abortado) bevore navegar ....

podría ser que el uso de temporizadores y no comprobar el estado del Webbrowser podría ser un problema

la siguiente cosa con la Webbrowser-Control es que no se puede usar en multithread/Backgroundworker ya que requiere ser STA .... (a menudo crea problemas con la aplicación que no responde)

la solución para "ful-contol" (analizar sitios web) usando. NET para mí, era usar WebRequest/Webresponse, puedes enviar el resultado de eso a Webbroswer.Document nuevamente si quieres que el DOM se ejecute "automáticamente", utilízalo multiproceso, configura fácilmente el tiempo de espera s/proxy que encontré más cómodo que usar Webbrowser-control.

Sin embargo i con éxito implementó un Webbrowser-Control analizar las páginas en otro proyecto con toques de aquí (How to Fix the Memory Leak in IE WebBrowser Control?)

otra "divertida" de espesor con Winforms de programación que descubrí es decir, que parece que un GC.Collect se activa cuando la ventana se minimiza y se abre de nuevo -> ¿disminuye esto el uso de la memoria? (Post maybee de Stefan también hace referencia a este tema)

+0

Lamentablemente intenté todo eso (las soluciones en su enlace, minimizando la aplicación) y nada funcionó. Incluso traté de borrar las entradas de TravelLog en vano. – Juan

Cuestiones relacionadas