【问题标题】:C# WeakReference useC# 弱引用使用
【发布时间】:2018-02-23 23:58:45
【问题描述】:

所以,我有这样的课程。 (如果有人问过这个问题,请原谅我,因为它看起来很笼统)

    public class Parent{

        private Child child1, child2;

        void someFunc(){
            child1 = new Child ();
            child2 = new Child ();
            child1.handle += parentHandle;
            child2.handle += parentHandle;
        }

        void parentHandle (Child sender)
        {
            Console.WriteLine ("Sender is: " + sender.ToString ());
        }
    }

    public class Child{

        public OnHandle handle;
        delegate void OnHandle(Child sender);

        void someChildFunc(){
            handle (this);
        }

    }

父级有一个对子级的引用,子级有一个对父级处理程序的引用。这是循环内存泄漏吗?我应该使用弱引用吗?

【问题讨论】:

  • 几乎所有暴露事件的类和处理该事件的类都是这种情况。它不是循环内存泄漏
  • 仅供参考 child1.handle += parentHandle; 在此示例中您订阅了同一事件两次
  • 我打算订阅 child2。谢谢。
  • .NET 垃圾收集器可以很好地处理引用中的循环;重要的是要避免从根引用这些循环,因为这些引用会由于内部的循环性质而使整个事物保持活力。

标签: c# memory-leaks circular-reference


【解决方案1】:

经典的弱引用用于创建不耗时的相对较大的内存对象。通过弱引用这些对象,我们让 GC 知道尽管有活动引用,但可以清除;如果再次调用引用的对象,则再次创建它。这是博客link。这样做的好处是避免占用你的内存并将其用于其他东西,并且当再次使用弱引用时,它会再次被创建(这可能必须很快)。

stackoverflow post 解释了为什么它不会导致内存泄漏(即使存在可能的循环引用)。

以下是代码 sn-p,它使用您的父类和子类并创建一个巨大的演示器对象,然后将其设置为 null。该过程重复 3 次,并在不同阶段测量内存。在初始内存碰撞之后,所有其他创建前、创建后和空后读数都不会改变,这意味着没有内存泄漏!。

    class Program
{
    static void Main(string[] args)
    {
        MonitorMemoryUsage();
        MonitorMemoryUsage();
        MonitorMemoryUsage();


        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }

    private static void MonitorMemoryUsage()
    {
        DisplayMemoryAfterGc("Before creation");
        var demonstrator = new Demonstrator();

        DisplayMemoryAfterGc("After creation");

        if (demonstrator.Children != null && demonstrator.Children.Count > 0)
        {
            demonstrator.Children = null;
            demonstrator.Parents = null;
            demonstrator = null;
        }


        Console.WriteLine(demonstrator == null);
        DisplayMemoryAfterGc("After null");
    }

    private static void DisplayMemoryAfterGc(string eventType)
    {
        GC.Collect();
        GC.WaitForFullGCComplete();
        var totalMemory = GC.GetTotalMemory(true);
        Console.WriteLine(eventType + ":" + totalMemory);
    }
}

public class Demonstrator
{
    public List<Parent> Parents { get; set; }
    public List<Child> Children { get; set; }

    public Demonstrator()
    {
        Parents = new List<Parent>();
        Children = new List<Child>();

        for (int i = 0; i < 10000; i++)
        {
            var parent = new Parent();

            Parents.Add(parent);

            Children.Add(parent._child1);
        }
    }

}

public class Parent
{

    public Child _child1, _child2;

    void someFunc()
    {
        _child1 = new Child();
        _child2 = new Child();
        _child1.handle += parentHandle;
    }

    void parentHandle(Child sender)
    {
        Console.WriteLine("Sender is: " + sender.ToString());
    }
}

public class Child
{

    public OnHandle handle;

    public delegate void OnHandle(Child sender);

    void someChildFunc()
    {
        handle(this);
    }

}

【讨论】:

    猜你喜欢
    • 2013-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多