Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/cmake/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WebBrowser control Automation C控制台应用程序测试中的内存泄漏_C#_Memory Leaks_Automation_Webbrowser Control_Sta - Fatal编程技术网

C# WebBrowser control Automation C控制台应用程序测试中的内存泄漏

C# WebBrowser control Automation C控制台应用程序测试中的内存泄漏,c#,memory-leaks,automation,webbrowser-control,sta,C#,Memory Leaks,Automation,Webbrowser Control,Sta,此发布测试代码的以下内容会导致内存泄漏。您能建议如何解决这个内存泄漏问题吗?仅供参考:我使用的是VS2010 Prof、.NETFramework4.0、Win7Ultimate和IE9。可使用C代码行激活测试代码: (new WebBrowser_STA_Test()).Main(); 多谢各位 p.S.WebBrowser control Automation C控制台应用程序测试代码: using System; using System.Windows.Forms; using Sys

此发布测试代码的以下内容会导致内存泄漏。您能建议如何解决这个内存泄漏问题吗?仅供参考:我使用的是VS2010 Prof、.NETFramework4.0、Win7Ultimate和IE9。可使用C代码行激活测试代码:

(new WebBrowser_STA_Test()).Main();
多谢各位

p.S.WebBrowser control Automation C控制台应用程序测试代码:

using System;
using System.Windows.Forms;
using System.Threading;
using NUnit.Framework;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace R_and_D_TestConsole
{
    public class WebBrowserThread : IDisposable 
    {
        private Action<string> _logger;
        public WebBrowserThread(Action<string> logger)
        {
            _logger = logger;
        }

        private void log(string message)
        {
            if (_logger != null) _logger(message);
        }

        private Thread _STA_Thread;

        public bool IsAlive
        {
            get
            {
                return (
                    _STA_Thread != null && 
                    _STA_Thread.IsAlive &&
                    !this.ThreadStoppingInProgress &&
                    !this.ThreadStopped
                    ); 
            }
        }

        public void Start()
        {
            log("Starting WebBrowser Thread...");

            _STA_Thread = new Thread(startBrowser);
            _STA_Thread.Name = "WebBrowser STA Thread";
            _STA_Thread.SetApartmentState(ApartmentState.STA);
            _STA_Thread.Start();

        }

        public WebBrowserHandler WebBrowserHandler { get; private set; }
        private void startBrowser()
        {
            log("WebBrowser Thread started.");

            WebBrowserHandler = new WebBrowserHandler(_logger);
            WebBrowserHandler.CreateBrowserInstance();

            Application.Run();
        }

        public bool ThreadStoppingInProgress { get; private set; }
        public bool ThreadStopped { get; private set; }
        public void Stop()
        {
            if (ThreadStoppingInProgress) return;

            try
            {
                ThreadStoppingInProgress = true;

                log("Stopping WebBrowser Thread...");

                log("Disposing WebBrowser Handler...");
                WebBrowserHandler.DisposeBrowserInstance();
                log("WebBrowser Handler partially disposed.");

                _STA_Thread.Abort();
                Application.ExitThread();
                log("WebBrowser Thread stopped.");
            }
            finally
            {
                ThreadStopped = true;
                ThreadStoppingInProgress = false;
            }

        }

        public bool Disposed { get; private set; }
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!this.Disposed)
            {
                if (disposing)
                {
                    if (WebBrowserHandler != null)
                    {
                        WebBrowserHandler.Dispose();
                        WebBrowserHandler = null;
                        log("WebBrowser Handler object instance and its child objects disposed completely (?)");
                    }

                    _logger = null;
                    _STA_Thread = null;
                }

                this.Disposed = true;
            }
        }

    }

    public class WebBrowserHandlerBase : IDisposable
    {
        protected ISynchronizeInvoke _invokeHelper;

        protected WebBrowser _webBrowser;

        private Action<string> _logger;
        public WebBrowserHandlerBase(Action<string> logger)
        {
            _logger = logger;
        }

        protected void log(string message)
        {
            if (_logger != null) _logger(message);
        }

        public bool Activated { get; private set; }
        public void CreateBrowserInstance()
        {

            _webBrowser = new WebBrowser();
            _webBrowser.Visible = true;
            _webBrowser.DocumentCompleted += webBrowser_DocumentCompleted;
            _webBrowser.ScriptErrorsSuppressed = true;

            _invokeHelper = _webBrowser as ISynchronizeInvoke;

            this.Activated = true;
        }

        public void DisposeBrowserInstance()
        {
            if (!this.Activated) return;

            Action dispose = () =>
                {
                    log("WebBrowserHandler.DisposeBrowserInstance (1)");
                    _webBrowser.DocumentCompleted -= webBrowser_DocumentCompleted;
                    // the following line results in floating runtime errors - commented...
                    //_webBrowser.Dispose();  

                    log("WebBrowserHandler.DisposeBrowserInstance (2)");
                };

            if (_invokeHelper.InvokeRequired)
            {
                IAsyncResult result = _invokeHelper.BeginInvoke(dispose, null);
                _invokeHelper.EndInvoke(result);
            }
            else dispose(); 

            this.Activated = false;
        }

        public bool Disposed { get; private set; }
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!this.Disposed)
            {
                if (disposing)
                {
                    if (_webBrowser != null)
                    {
                        // The following line results in runtime error:
                        //   'COM object that has been separated from its underlying RCW cannot be used.'
                        //_webBrowser.Dispose();
                        log("Releasing WebBrowser ActiveX instance...");
                        if (_webBrowser.ActiveXInstance != null) Marshal.ReleaseComObject(_webBrowser.ActiveXInstance);
                        _webBrowser = null;
                    }

                    _logger = null;
                }

                this.Disposed = true;
            }
        }

        public bool NavigationCompleted { get; protected set; }
        public virtual void Navigate_Async(string url) { }
        public virtual void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) {}
    }

    public class WebBrowserHandler : WebBrowserHandlerBase 
    {
        public WebBrowserHandler(Action<string> logger):base(logger) {}

        public override void Navigate_Async(string url)
        {
            if (!this.Activated) throw new ApplicationException(string.Format("{0} is not yet activated.", this.GetType().Name) ) ; 

            Action<string> navigate = (x) =>
                {
                    NavigationCompleted = false;
                    _webBrowser.Navigate(x); 
                };

            if (_webBrowser.InvokeRequired) _webBrowser.Invoke(navigate, new object[] { url } ); 
            else navigate(url);
        }

        public override void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            log(string.Format(" *** webBrowser_DocumentCompleted: {0} {1}", _webBrowser.ReadyState,  e.Url));

            if (NavigationCompleted) return;

            NavigationCompleted = _webBrowser.ReadyState == WebBrowserReadyState.Complete;

            if (NavigationCompleted)
            {
                log(string.Format(" *** {0} '{1}'", _webBrowser.DocumentText.Length, _webBrowser.DocumentTitle));       
            }
        }
    }

    public class WebBrowser_STA_Test
    {

        private void log(string message)
        {
            System.Console.WriteLine("[{0}] - {1}", System.Threading.Thread.CurrentThread.ManagedThreadId, message);   
        }

        public void Main()
        {
            for (int i =1; i <= 10; i++)
            {
                test();
                GC.Collect(); 
            }
        }

        private void test()
        {
            log("Test started.");

            foreach (string url in new string[] 
                   { 
                   "http://www.google.com", 
                   "http://www.bing.com", 
                   "http://www.yandex.ru" 
                   })
            {

                log(string.Format("+++ TEST URL = '{0}' +++", url));

                bool navigateMethodCalled = false;

                using (WebBrowserThread _wbTest = new WebBrowserThread(log))
                {
                    _wbTest.Start();

                    Application.DoEvents();

                    while (_wbTest.IsAlive)
                    {
                        if (_wbTest.IsAlive &&
                            _wbTest.WebBrowserHandler != null &&
                            _wbTest.WebBrowserHandler.Activated &&
                            !navigateMethodCalled) 
                        { navigateMethodCalled = true; _wbTest.WebBrowserHandler.Navigate_Async(url); }

                        if (_wbTest.IsAlive &&
                            _wbTest.WebBrowserHandler != null &&
                            _wbTest.WebBrowserHandler.NavigationCompleted) _wbTest.Stop();

                        Thread.Sleep(500);
                    }
                }

                log(string.Format("--- TEST URL = '{0}' ---\n", url));
            }

            log("Test finished.");

        }

    }
}

在完成的函数中粘贴以下内容

System.Diagnostics.Process loProcess = System.Diagnostics.Process.GetCurrentProcess();
try
{
    loProcess.MaxWorkingSet = (IntPtr)((int)loProcess.MaxWorkingSet - 1);
    loProcess.MinWorkingSet = (IntPtr)((int)loProcess.MinWorkingSet - 1);
}
catch (System.Exception)
{
    loProcess.MaxWorkingSet = (IntPtr)((int)1413120);
    loProcess.MinWorkingSet = (IntPtr)((int)204800);
}

请注意,使用MaxWorkingSet和MinWorkingSet将强制应用程序使用虚拟内存,而不是实际RAM。这会导致磁盘抖动,可能无法解决问题

我已经找了好几个星期了,但我没有找到这个问题的最终解决方案

即使销毁web浏览器对象也不会释放内存。据我所知,唯一可靠的方法是重新启动应用程序

然而,在浏览“网络”时,我确实发现了这个有趣的页面:

…他们声称有一个解决方案,尽管我没有尝试过,因为它是用C语言编写的,而我的应用程序是用vb.net编写的


不幸的是,没有一个基于web的转换器愿意在不崩溃的情况下将代码转换为vb.net,而且由于我在c方面很差劲,我自己也无法转换它

对OP的一点解释总是很好的,可以证明你的观点或解释你的方法:谢谢你的评论。我已经看过了您提到的CodeProject文章和您提供的JavaScript代码注入示例——我可能会尝试使用它。但到目前为止,这个主题还没有出现在我当前的主流待办事项列表中,所以我可能需要一些时间来检查提议的解决方案在这里是否有效。我还想过尝试使用一个专用的应用程序域来运行一个Web浏览器实例,并在完成后与AppDomain一起杀死它。。。