15

コード

using System;
internal static class Test
{
    private static void Main()
    {
        try
        {
            Console.WriteLine("{0,10}: Start point", GC.GetTotalMemory(true));
            Action simpleDelegate = SimpleDelegate;
            Console.WriteLine("{0,10}: Simple delegate created", GC.GetTotalMemory(true));
            Action simpleCombinedDelegate = simpleDelegate + simpleDelegate + simpleDelegate;
            Console.WriteLine("{0,10}: Simple combined delegate created", GC.GetTotalMemory(true));
            byte[] bigManagedResource = new byte[100000000];
            Console.WriteLine("{0,10}: Big managed resource created", GC.GetTotalMemory(true));
            Action bigManagedResourceDelegate = bigManagedResource.BigManagedResourceDelegate;
            Console.WriteLine("{0,10}: Big managed resource delegate created", GC.GetTotalMemory(true));
            Action bigCombinedDelegate = simpleCombinedDelegate + bigManagedResourceDelegate;
            Console.WriteLine("{0,10}: Big combined delegate created", GC.GetTotalMemory(true));
            GC.KeepAlive(bigManagedResource);
            bigManagedResource = null;
            GC.KeepAlive(bigManagedResourceDelegate);
            bigManagedResourceDelegate = null;
            GC.KeepAlive(bigCombinedDelegate);
            bigCombinedDelegate = null;
            Console.WriteLine("{0,10}: Big managed resource, big managed resource delegate and big combined delegate removed, but memory not freed", GC.GetTotalMemory(true));
            GC.KeepAlive(simpleCombinedDelegate);
            simpleCombinedDelegate = null;
            Console.WriteLine("{0,10}: Simple combined delegate removed, memory freed, at last", GC.GetTotalMemory(true));
            GC.KeepAlive(simpleDelegate);
            simpleDelegate = null;
            Console.WriteLine("{0,10}: Simple delegate removed", GC.GetTotalMemory(true));
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
        Console.ReadKey(true);
    }
    private static void SimpleDelegate() { }
    private static void BigManagedResourceDelegate(this byte[] array) { }
}

出力

GC.TotalMemory(true)
    105776: Start point
    191264: Simple delegate created
    191328: Simple combined delegate created
 100191344: Big managed resource created
 100191780: Big managed resource delegate created
 100191812: Big combined delegate created
 100191780: Big managed resource, big managed resource delegate and big combined delegate removed, but memory not freed
    191668: Simple combined delegate removed, memory freed, at last
    191636: Simple delegate removed
4

2 に答える 2

17

興味深いケース。解決策は次のとおりです。

ここに画像の説明を入力してください

デリゲートの組み合わせは、観察上純粋です。デリゲートは外部に対して不変であるように見えます。ただし、内部的には、既存のデリゲートが変更されています。これらは、特定の条件下で、_invocationListパフォーマンス上の理由から同じものを共有します(少数のデリゲートが同じイベントに接続されるシナリオに最適化されます)。残念ながら、_invocationList参照simpleCombinedDelegateの場合、bigMgdResDelegateこれによりメモリが存続します。

于 2012-05-09T21:27:25.187 に答える
1

ここで要点を見逃しているかもしれませんが、ガベージコレクションは設計上非決定論的です。エルゴ、いつメモリを再利用するかを決めるのは.NETFramework次第です。

単純なループでGC.GetTotalMemoryを実行して、さまざまな数値を取得できます。ドキュメントには、返される数値が概算であると指定されているため、おそらく驚くことではありません。

于 2012-05-09T21:34:28.313 に答える