2

List (Of Object) に収集されたオブジェクトをきれいにして破棄する効率的な方法は何ですか?

List.Clear() メソッドを呼び出すと、それによって収集されたすべてのオブジェクトが自動的にクリーンアップされますか?

例として、以下の例を考えてみましょう

public partial class Form1 : Form
{
    FontCollection m_fontCollection;

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        m_fontCollection = new FontCollection();
        for (int i = 0; i < 5000; i++)
        {
            Font font = new Font("Arial", 23);

            FontImpl impl = new FontImpl(font, Color.Black);
            impl.AfterChange += 
                new FontImpl.AfterChangeHandler(impl_AfterChange);

            m_fontCollection.Add(impl);
        }

        m_fontCollection.Dispose();
        MessageBox.Show("TakeSnap");
    }

    void impl_AfterChange()
    {
        throw new NotImplementedException();
    }
}

public class FontCollection : IEnumerable, IDisposable
{
    IList<FontImpl> m_Implementation = new List<FontImpl>();

    internal void Add(FontImpl impl)
    {
        this.m_Implementation.Add(impl);
    }

    public IEnumerator GetEnumerator()
    {
        return this.m_Implementation.GetEnumerator();
    }

    public void Dispose()
    {
        m_Implementation.Clear();
        m_Implementation = null;
    }
}

public class FontImpl
{
    private Font m_Font;
    private Color m_color;

    public FontImpl(Font newFont, Color newColcor)
    {
        m_Font = newFont;
        m_color = newColcor;
    }

    public event AfterChangeHandler AfterChange;

    public delegate void AfterChangeHandler();
}

上記のアプリケーション ANTS メモリ プロファイラを実行すると、Font と FontFamily のメモリ リーク (画面をアップロードできませんでした) と、これらのリークを削除する方法を確認できました。

4

4 に答える 4

3

一般に、ガベージ コレクションとそれがいつ発生するかについて心配する必要はありません。オブジェクトへの参照がゼロの場合、そのオブジェクトは GC の対象となります。

ただし、注意する必要IDisposableがあるのはオブジェクトです。オブジェクトを使い終わったらIDisposable、本当にそれを呼び出す必要がありますDispose()。オブジェクトが関数のローカル スコープ内に存在する場合、usingブロックを使用するとこれが簡単になります。

using (var resource = new SomeIDisposable()) {
    // use resource

    // resource.Dispose() is automatically called, *even if* an exception
    // is thrown.
}

オブジェクトへの「ダングリング参照」が発生することでメモリ リークが発生し、ガベージ コレクションが妨げられる可能性があります。ほとんどの場合、これの原因はイベント ハンドラーにあります。object によって公開されたイベントをサブスクライブすると、 objectのAイベント ハンドラを使用して、 への参照が取得されます。BAB

class B {
    void hook_up_to(A a) {
        a.SomeEvent += Handler;     // `a` gets a reference to `this`
    }

    void Handler(object sender, EventArgs e) {
    }
}

class Program {
    private A _a = new A();

    static void SomeMethod() {
        var b = new B();

        b.hook_up_to(_a);    // _a now has a reference to b

        // b goes out of scope.
    }
}

通常、bスコープ外になると、それが参照するオブジェクトはガベージ コレクションの対象になります。ただし、この場合、bメンバー variable によって公開されたイベントに接続され、_a_aの参照が取得されましたb。現在、 への未解決の参照が 1 つありますがbこれはクリアできず、GC の対象外です。これはメモリ リークです。b

1bこの場合の唯一の参照方法thisは、イベント ハンドラが起動された場合のポインタです。

于 2012-12-21T05:39:32.953 に答える
1

IDisposableクラスに実装する必要はありません。一般に、クラスを実装する必要があるのは、破棄する必要のある他のクラス (データベースやネットワーク接続、管理されていないオブジェクトなど) がクラスIDisposableに含まれている場合のみです。

あなたの例では、そのメソッド内で完全に作成および破棄しているため、内でローカル変数を作成m_fontCollectionすることを検討することをお勧めします。ローカルにすると、終了するとガベージコレクションされます...それへの参照が残っていない場合(実際にはこの場合はありません)button1_Clickbutton1_Click

于 2012-12-21T05:43:55.917 に答える
0

Clearは、リストからすべてを削除するだけです。あなたの場合、IDisposableオブジェクトのリストがあり、リスト内のすべてのアイテムに対してDisposeを呼び出す必要があります。Clearを呼び出してもそれは行われません。

FontImplはIDisposableオブジェクトを管理するため、IDisposableを実装する必要があります。

 public void Dispose() {
      if (m_Font != null) {
          m_Font.Dispose();
          m_Font = null;
      }
 }

また、FontCollectionDisposeは次のようになります。

public void Dispose()
{
    foreach(FontImpl font in m_Implementation) {
        font.Dispose();
    }
    m_Implementation.Clear();
    m_Implementation = null;
}
于 2012-12-21T06:00:14.450 に答える
0

示したコードの場合、Font実装するオブジェクトがあるためIDisposable、破棄する必要があります。これらのオブジェクトはFontImplクラスによって管理されているため、FontImplを実装する必要がありますIDisposable。クラスには、使い捨てになっているはずFontCollectionのオブジェクトのリストが含まれているため、を実装する必要があります。FontImplFontCollectionIDisposable

IDisposableパターンを読む必要があります(このSOの回答は、いくつかの優れた情報を提供します-https://stackoverflow.com/a/538238/416574)。

FontCollectionそうは言っても、提供したコードスニペットからは、リストをラップするためにクラス以外から何かを得ているようには見えません。そのクラスで他にやろうとしていることがない限り、私はメンバー変数としてリストを持っているだけです。そうDisposeすれば、フォームのメソッドでリストをウォークしてFontImplオブジェクトを破棄できます。二重廃棄から保護したい場合は、すべてを廃棄した後、リストを空にしてください。

于 2012-12-21T06:00:19.820 に答える