2

So, i have a class like this. (Excuse me if someone has asked this question before because it seems pretty generic)

    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);
        }

    }

The parent has a reference to the child, the child has a reference to the parent's handler. Is this a circular memory leak? Should I be using weak references?

TatiOverflow
  • 1,071
  • 2
  • 16
  • 23
  • 1
    This is the case with pretty much any class which is exposing an event and the class which is having handler to that event. Its not circular memory leak – Chetan Feb 24 '18 at 00:06
  • Just FYI `child1.handle += parentHandle;` you are subscribing to the same event twice in this exmaple – TheGeneral Feb 24 '18 at 00:26
  • I meant to subscribe to child2. thanks. – TatiOverflow Feb 25 '18 at 00:12
  • The .NET garbage collector handles cycles in references just fine; the important thing is to avoid references from roots to these cycles as those references will, due to the cyclic nature inside, keep the whole thing alive. – Lasse V. Karlsen Feb 27 '18 at 07:15

1 Answers1

1

Classically WeakReferencing is used for relatively large memory objects which are not time consuming to create. By weak-referencing such objects we let GC know that it is okay to wipe out despite the active reference; if the referenced object is called again then it is created again. Here is the blog link . The benefit is to avoid keeping your memory occupied and putting it at use for other stuff and when the weak reference is used again then it is created again (which presumably has to be fast).

This stackoverflow post explains why it isn't going to cause memory leaks (even if there is a possible circular reference).

Following is the code snippet which uses your parent and child classes and creates a huge demonstrator object then later sets it to null. The process is repeated three times and memory is measured at different stages. After initial memory bump, all other pre-creation post-creation and post-null readings don't change which means no memory leaking!.

    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);
    }

}
sbp
  • 913
  • 8
  • 19