31

C# Winform アプリケーションに WebBrowser コントロールを埋め込もうとしています。これは簡単に聞こえます。しかし、Navigate メソッドを呼び出すたびに、WebBrowser コントロールが大量のメモリを消費することがわかりました。メモリが解放されることはありません。メモリ使用量はどんどん増えていきます…</p>

ネット上にはまったく同じ問題を抱えている人がたくさんいますが、満足のいく答えはまだ見つかりません. これは、私がこれまでに見つけたこの問題に関する最高の議論です:

IE WebBrowser コントロールでのメモリ リーク

ある人は、問題を解決するために IE8 へのアップグレードを提案しました。

ただし、ユーザーが最新の IE バージョンをインストールしているかどうかに関係なく機能するソリューションが必要です。私はユーザー環境を制御できません。

WebBrowser コントロールによって取得されたメモリを解放する方法を知っている人はいますか? 回避策はありますか? WebBrowser コントロールに代わるものはありますか?

更新: さらにいくつかのテストを行いました。職場では、Windows XP と IE6 を実行しています。メモリはそこで成長していません。ナビゲートメソッドを呼び出すとメモリが増えますが、しばらくすると解放されます。自宅では Vista を実行しており、IE8 にアップグレードしています。ここでも、問題はもう見られません。問題はIE7に固有のようです。したがって、質問は「IE7がインストールされているときにIE WebBrowser Controlでメモリリークを修正する方法」に言い換える必要があります。この問題が IE7 に固有のものであることを確認できる人はいますか?

4

18 に答える 18

12

私のアプリは、ナビゲートするときに常にメモリを消費し、もう解放しませんでした。ここで解決策を見つけます: http://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/88c21427-e765-46e8-833d-6021ef79e0c8

完全を期すために、注目すべき抜粋を投稿してください。

-- in class definition

    [DllImport("KERNEL32.DLL", EntryPoint = "SetProcessWorkingSetSize", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
    internal static extern bool SetProcessWorkingSetSize(IntPtr pProcess, int dwMinimumWorkingSetSize, int dwMaximumWorkingSetSize);

    [DllImport("KERNEL32.DLL", EntryPoint = "GetCurrentProcess", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
    internal static extern IntPtr GetCurrentProcess();

-- メモリを減らしたいときに呼び出すコード

        IntPtr pHandle = GetCurrentProcess();
        SetProcessWorkingSetSize(pHandle, -1, -1);

すべての名誉: http://social.msdn.microsoft.com/profile/mike_t2e/?type=forum&referrer=http://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/88c21427-e765 -46e8-833d-6021ef79e0c8 ソリューションを投稿してください。

そして http://ict-engineer.blogspot.com/2010/10/net-webbrowser-control-memory-leak.html SEO を正しく行うため、私はそれを見つけることができました ;)

挨拶

編集:これが問題をすばやく解決するのに役立つ場合-良い。ただし、アプリケーションの設計、使用するパターンがある場合はそれを超えて、それをさらに長く構築する場合はリファクタリングする必要があります....

于 2011-06-06T21:10:30.563 に答える
8

基本的なアイデアは、

「自殺して生まれ変わる」

Windows はすべてのメモリの問題を解決します。

ただし、最初にアプリケーションを閉じると、新しいアプリケーションを開始できなくなります。

したがって、新しいものを開始し、古いものを閉じます。

最初に新しいものをオンにし、古いものをオフにします。


public void SOLVE_ALL_MY_MEMORY_PROBLEM()
{
  System.Diagnostics.Process.Start("MyProgram.exe");
  Application.Exit();
}

https://www.youtube.com/watch?v=aTBlKRzNf74

パラメータがあれば、

public void SOLVE_ALL_MY_MEMORY_PROBLEM()
{
  System.Diagnostics.Process.Start("MyProgram.exe", "PARA_para_dance");
  Application.Exit();
}

Program.cs に移動します。

    static void Main(string[] args)
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        if(args.Count() > 0)
            Application.Run(new Form1(args[0]));
        else
            Application.Run(new Form1());
    }

Form1.cs に移動し、別の Form1() を作成します。

    public Form1()
    {
        InitializeComponent();
    }

    public Form1(string dance_name)
    {
        InitializeComponent();

        ...
    }

または、一時ファイルを使用できます!!!

于 2015-06-12T17:41:29.237 に答える
7

結果を複製するために、Web ブラウザー コントロールを備えた単純なアプリを作成しました。私が見つけたのは、はい、ページに移動するたびに、使用されているメモリが大幅に増加するということでした. ただし、これはメモリ リークではありません。ナビゲートを続けると、しばらくするとメモリが大幅に低下し、ガベージ コレクタが原因であることがわかります。それを証明するために、Navigate を呼び出すたびにガベージ コレクターに収集を強制しました。使用されたメモリ全体は、すべての Navigate 呼び出しの後、ほぼ同じ量のままでした。

したがって、「ナビゲート」するたびにメモリを消費しますが、メモリリークではなく、メモリが解放されます。あまりにも速くかき集めている場合は、GC.Collect(); を呼び出してください。

于 2009-05-25T01:41:48.390 に答える
3

Trident の代わりに Gecko (Firefox が使用するエンジン) を使用する代替コントロールがあり、MSHTML インターフェイスで非常にうまく機能します。

ページは Gecko でレンダリングされ、ブラウザの設定、プラグイン、セキュリティ、およびその他のカスタマイズ可能な機能を完全に制御できます。

欠点は、アプリと一緒に Gecko を出荷する必要があることです。私が最後に使用したのは Firefox 2 に相当するもので、約 8MB でした。

私はかなり前に、IE と Firefox のレンダリングを比較し、CSS の編集に合わせて更新するアプリをリリースしました。Web ブラウザ コントロールで発生したメモリの問題には遭遇しませんでしたが、Gecko コントロールは非常に簡単に操作できることがわかりました。.net WebBrowser コントロールと同じマネージ ラッパー クラスはありませんが、それを回避するのは簡単です。

于 2009-05-24T19:53:20.370 に答える
2

Navigate() メソッドは、GoBack() メソッドを使用できるため、アクセスしたすべてのページをメモリに保持しているようですが、実際には「メモリ リーク」はありません。プログラムが同じ URL に繰り返しアクセスします。「メモリ リーク」の問題は、Navigate() メソッドの Refresh() メソッド インスタンスを使用し、その後に GC.Collect() を使用することで解消できます。コードは次のとおりです。

       try
        {
            if (webBrowser.Url.Equals("about:blank")) //first visit
            {
                webBrowser.Navigate(new Uri("http://url"));
            }
            else
            {
                webBrowser.Refresh(WebBrowserRefreshOption.Completely);
            }
        }
        catch (System.UriFormatException)
        {
            return;
        }
        System.GC.Collect(); // may be omitted, Windows can do this automatically
于 2014-03-22T00:14:58.117 に答える
1

WebBrowser コントロールに既知のメモリ リークがあります。次の Microsoft KB 記事 - KB893629を参照してください。

于 2011-01-03T15:58:57.683 に答える
1

会社で使用されているさまざまなイントラネット ページ用の小さな「スライドショー」アプリケーションを作成しているときに、この問題に遭遇しました。私が見つけた最も簡単な解決策は、一定時間後 (私の場合は 1 時間) にアプリケーションを再起動することでした。このソリューションは、ブラウザとのユーザー インタラクションがあまりなかったので、私たちにとってはうまくいきました。

Public Class MyApplication

    Private _AppTimer As Timers.Timer

    Public Sub New()
        _AppTimer = New Timers.Timer()
        _AppTimer.Interval = 1 * 60 * 60 * 1000 '1 Hour * 60 Min * 60 Sec * 1000 Milli

        AddHandler _AppTimer.Elapsed, AddressOf AppTimer_Elapsed

        _AppTimer.Start()
    End Sub

    Private Sub AppTimer_Elapsed(s As Object, e As Timers.ElapsedEventArgs)
        Application.Restart()
    End Sub

End Class

もちろん、これはデータの永続化メカニズムが整っていることを前提としています。

于 2014-03-14T15:55:11.327 に答える
1

私はインターネット全体を見ましたが、この問題に対する答えを見つけることができませんでした。以下を使用して修正しました:

Protected Sub disposeBrowers()
    If debug Then debugTrace()
    If Me.InvokeRequired Then
        Me.Invoke(New simple(AddressOf disposeBrowers))
    Else
        Dim webCliffNavigate As String = webCliff.Url.AbsoluteUri

        'Dim webdollarNavigate As String = webDollar.Url.AbsoluteUri
        Me.splContainerMain.SuspendLayout()
        Me.splCliffDwellers.Panel2.Controls.Remove(webCliff)
        Me.splDollars.Panel2.Controls.Remove(webDollar)
        RemoveHandler webCliff.DocumentCompleted, AddressOf webCliff_DocumentCompleted
        RemoveHandler webDollar.DocumentCompleted, AddressOf webDollar_DocumentCompleted
        RemoveHandler webCliff.GotFocus, AddressOf setDisposeEvent
        RemoveHandler webCliff.LostFocus, AddressOf setDisposeEvent
        RemoveHandler webDollar.GotFocus, AddressOf setDisposeEvent
        RemoveHandler webDollar.LostFocus, AddressOf setDisposeEvent
        webCliff.Stop()
        webDollar.Stop()

        Dim tmpWeb As SHDocVw.WebBrowser = webCliff.ActiveXInstance
        System.Runtime.InteropServices.Marshal.ReleaseComObject(tmpWeb)
        webCliff.Dispose()

        tmpWeb = webDollar.ActiveXInstance
        System.Runtime.InteropServices.Marshal.ReleaseComObject(tmpWeb)
        webDollar.Dispose()

        webCliff = Nothing
        webDollar = Nothing
        GC.AddMemoryPressure(50000)
        GC.Collect()
        GC.WaitForPendingFinalizers()
        GC.Collect()
        GC.WaitForFullGCComplete()
        GC.Collect()
        GC.RemoveMemoryPressure(50000)
        webCliff = New WebBrowser()
        webDollar = New WebBrowser()
        webCliff.CausesValidation = False
        webCliff.Dock = DockStyle.Fill
        webDollar.CausesValidation = webCliff.CausesValidation
        webDollar.Dock = webCliff.Dock
        webDollar.ScriptErrorsSuppressed = True
        webDollar.Visible = True
        webCliff.Visible = True
        Me.splCliffDwellers.Panel2.Controls.Add(webCliff)
        Me.splDollars.Panel2.Controls.Add(webDollar)
        Me.splContainerMain.ResumeLayout()

        'vb.net for some reason automatically recreates these and the below is not needed
        'AddHandler webCliff.DocumentCompleted, AddressOf webCliff_DocumentCompleted
        'AddHandler webDollar.DocumentCompleted, AddressOf webDollar_DocumentCompleted
        'AddHandler webCliff.GotFocus, AddressOf setDisposeEvent
        'AddHandler webCliff.LostFocus, AddressOf setDisposeEvent
        'AddHandler webDollar.GotFocus, AddressOf setDisposeEvent
        'AddHandler webDollar.LostFocus, AddressOf setDisposeEvent

        webCliff.Navigate(webCliffNavigate)
        'webDollar.Navigate(webdollarNavigate)
        disposeOfBrowsers = Now.AddMinutes(20)
    End If
End Sub

これが最も美しいまたは完璧な解決策ではないことはわかっていますが、私にとっては非常にうまく機能しました。-- レイラ

于 2012-02-21T14:14:09.990 に答える
1

この質問は、長い間答えられていないと思います。同じ質問がありますが、決定的な答えではない非常に多くのスレッド。

この問題の回避策を見つけたので、まだこの問題に直面している皆さんと共有したいと思います.

ステップ 1: form2 と言う新しいフォームを作成し、それに Web ブラウザー コントロールを追加します。step2: webbrowser コントロールがある form1 で、それを削除します。step3: ここで、Form2 に移動し、この Web ブラウザー コントロールのアクセス修飾子をパブリックにして、Form1 でアクセスできるようにします。 step4: form1 でパネルを作成し、form2 のオブジェクトを作成して、これをパネルに追加します。Form2 frm = 新しい Form2 (); frm.TopLevel = false; frm.Show(); panel1.Controls.Add(から); step5: 以下のコードを定期的に呼び出す frm.Controls.Remove(frm.webBrowser1); frm.Dispose();

それでおしまい。これを実行すると、Web ブラウザー コントロールが読み込まれ、一定の間隔で破棄され、アプリケーションがハングすることがなくなります。

以下のコードを追加して、より効率的にすることができます。

    IntPtr pHandle = GetCurrentProcess();
    SetProcessWorkingSetSize(pHandle, -1, -1);


    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();
于 2013-05-09T05:42:31.580 に答える
0

私は同じような問題を抱えていました。動的ページをスクレイピングするために、Web ブラウザー経由で 5000 を超えるナビゲーション要求を送信していました。約 50 回のリクエストの後、各リクエストの後にナビゲーション リクエストのメモリ使用量が解放されなかったため、メモリが不足しました。ナビゲーション後に webBrowser.Dispose() を使用したところ、問題は解決しました。IE7とか関係ありません。私はIE 11を使用していますが、同じ問題が発生しました。それは、ナビゲーション オブジェクトを破棄していなかったためです。お役に立てれば。

于 2015-06-17T19:30:09.113 に答える
0

別の方法として、新しいページに移動する代わりに、system.oi.streamreader/writer オブジェクトを使用して同じ html ページを書き直して、更新を呼び出しました。明らかに、ブラウザーのコンテンツがオンラインで提供されている状況では機能しませんが、私にとってはうまく機能しています。

また、現在、.net アプリ内で JavaScript を介してレポートを提供するために、同時にアクティブな 8 つ以上のブラウザー コントロールを使用しています。ユーザーが 1 つのブラウザーをアクティブにすると、他のブラウザーが指している html がクリアされ、ブラウザーが更新されます。これら 2 つの方法で 8 つのブラウザーを実行すると、わずか 3 つのタブを開くだけで、Firefox のメモリ使用量を十分に抑えることができます。

于 2009-06-23T14:48:39.173 に答える
0

「using」キーワードを使用して WebBrowser コントロールを宣言するだけです。Navigate() メソッドを呼び出すときにメモリ リークが発生しなくなります。私はそれをテストしたところ、うまくいきました。

using (var webBrowser = new System.Windows.Forms.WebBrowser())
{
    webBrowser.Navigate(url);
}
于 2018-04-27T21:48:24.347 に答える
0

アプリケーションで Web コントロールを使用していますが、アプリケーションが 1 つのページにしか移動しないため、あなたが言及した問題に気づいていません。実際にはラッパーである別の Web コントロールがあり、同じ問題があるかどうかはわかりません。ここで見つけることができます。

于 2009-05-24T19:32:37.683 に答える
-1

ページの読み込み後に次のコードを貼り付けます

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);
}
于 2012-06-22T11:10:25.077 に答える