0

構成 (OS、グラフィックス カード、およびメモリ) が異なる特定のマシンでは、OutOfMemory 例外が発生します。一部のテストでは、消費される仮想メモリが大幅に増加していないことが示されました。それは、例外が発生するコードの一部です。

public override Size GetPreferredSize(Size proposedSize)
{
    try
    {
        using (Graphics g = this.CreateGraphics())
        {
            SizeF measured = g.MeasureString(this.Text, this.Font); // <= OutOfMemoryException
            measured += new SizeF(1, 1);
            return measured.ToSize();
        }
    }
    catch (OutOfMemoryException oom)
    {
        System.Diagnostics.Trace.WriteLine(oom.ToString());
    }
    return proposedSize;
}

クラスは label から直接派生します。

CreateGraphics() は、GDI+ 関数 GdipCreateFromHWND を呼び出します。これは、場合によっては、私が直面している OutOfMemoryException を発生させるステータス (3) を返す可能性があります。

[EditorBrowsable(EditorBrowsableState.Advanced), SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
public static Graphics FromHwndInternal(IntPtr hwnd)
{
    IntPtr zero = IntPtr.Zero;
    int status = SafeNativeMethods.Gdip.GdipCreateFromHWND(new HandleRef(null, hwnd), out zero);
    if (status != 0)
    {
        throw SafeNativeMethods.Gdip.StatusException(status); // status = 3 throws an OutOfMemoryException with text "Out of memory"
    }
    return new Graphics(zero);
}

しかし、残念ながら、メモリ不足を返す関数とケースに関するドキュメントは見つかりませんでした。

この問題は、少なくとも 1 台の顧客のマシンで非常に高速に再現可能です。彼がしなければならないことは、この派生した Label の 1 つが配置され、WebBrowser コントロールにコンテンツを表示するために使用される新しいウィンドウを作成するボタンをクリックすることだけです。

例外の理由を見つけるのに役立つアイデアがあれば、それは素晴らしいことです!

乾杯、マイケル

4

2 に答える 2

1

非解決策: を使用しないでくださいGraphics。アプリケーションがSetCompatibleTextRenderingDefault(false)起動時に実行される場合 (テキストのレンダリングが向上するため)、の代わりにTextRenderer.MeasureTextMeasureStringを使用する必要があります。そうしないと、測定に GDI+ を使用し、描画に GDI を使用して、実際のレンダリングと測定の間に不一致が生じるためです。

別の解決策は、Graphicsオブジェクトをキャッシュするのではなく、サイズをキャッシュすることです。proposedSizeとにかく使用していないので、TextまたはFontプロパティが変更されるたびにテキストを測定し、キャッシュされた値を に返しますGetPreferredSize

于 2014-04-04T19:18:50.217 に答える
0

これはうまくいくかもしれません

private Graphics _graphics;
protected override void OnPaint(PaintEventArgs e)
{
    _graphics = e.Graphics;
    base.OnPaint(e);
}

public override Size GetPreferredSize(Size proposedSize)
{
    try
    {
        SizeF measured = _graphics.MeasureString(this.Text, this.Font);
        measured += new SizeF(1, 1);
        return measured.ToSize();
    }
    catch (OutOfMemoryException oom)
    {
        System.Diagnostics.Trace.WriteLine(oom.ToString());
    }
    return proposedSize;
}

http://msdn.microsoft.com/en-us/library/system.windows.forms.control.creategraphics.aspxのドキュメントには、 「Graphics のような非ビジュアル メソッドを使用する場合を除いて、再利用のために Graphics オブジェクトをキャッシュすることはできない」と記載されています。これはまさにあなたがやろうとしていることです。コントロールが描画される前に GetPreferredSize が呼び出された場合、これは失敗し、Graphics オブジェクトを Dispose する必要がありますが、これは実行可能なソリューションに近づくのに役立つ可能性があります。

于 2013-05-28T19:52:00.797 に答える