In fact, memory leaks have always been a headache. In a language with GC, this situation has improved a lot, but there may still be problems.

First, what is the memory leak?

Memory leaks don’t mean that the memory is broken, nor does it mean that the memory is not plugged in. In short, the memory leak is that the memory occupied by your program is not released as you expected.

So what is the time you are looking for? It is important to understand this. If an object takes up memory as long as the program containing it, you don’t expect it. Then you can think of it as a memory leak. The specific examples are as follows:

Class Button {
   public  void OnClick( object sender, EventArgs e) {
    ...
  }
}

Class Program {
   static  event EventHandler ButtonClick;
   static  void Main( string [] args) { 
      Button button = new Button();
      ButtonClick += button.OnClick;    
  }
}

In the above code, we used a static event, and the life cycle of the static member is from the time the AppDomain is loaded until the AppDomain is uninstalled, that is, under normal circumstances, if the process is not closed, forgetting to cancel the registration event. Then , the object referenced by the EventHandler delegate contained in the ButtonClick event will persist until the end of the process, which causes a memory leak. This is one of the most common memory leak issues in .NET. Later I will continue to talk about how to solve the leak caused by this incident.

Second, the way of memory recycling

1, reference counting

The meaning of a reference count is to keep track of the number of times each value is referenced. When a variable is declared and a reference type value is assigned to the variable, the number of references to this value is 1. If the same value is assigned to another variable, the number of references to the value is increased by one. Conversely, if the variable containing the reference to this value gets another value, the number of references to this value is decremented by 1. When the number of references to this value becomes 0, there is no way to access this value again, so you can reclaim the memory space it occupies. This way, when the garbage collector is run again next time, it will release the memory occupied by the values ​​with zero reference times.

The way to reclaim the native object memory in Javascript in IE6 is to determine whether an object is garbage by checking whether the object has a reference. Prior to IE9, objects in the BOM and DOM were implemented in the form of COM objects using C++, and the garbage collection mechanism of COM objects also used the reference counting strategy. This method usually causes memory leaks due to circular references, that is, A refers to B, and B also refers to A. There is also the problem of such circular references in Objective-C. Solution Objective-C, is marked as a weak one, we can introduce reference , in the introduction to the Objective-C autoselect mode.

2, mark clearing method (mark-weep)

C# uses the markup method to reclaim memory. All objects are marked, and they are marked once and are no longer marked. Determining whether an object is garbage depends on whether there is a reference, but whether it is referenced by root.

The type of root has variables in registers, variables on the thread stack, static variables, and so on.

Let’s look at a normal object graph with a circular reference.

We extract some of the diagrams

In the implementation of the markup cleanup strategy, since the local3 is popped and the scope is left after the function is executed, this mutual reference is not a problem in the markup cleanup method.

It’s easy to see that because every object is marked, creating a large number of small objects can put pressure on the Mark phase. It’s worth noting that in the mark and weep phases of the GC, all threads are suspended, so creating a large number of threads can also cause problems for the GC. I will discuss this issue later.

Third, weak references solve some problems

As mentioned earlier, forgetting to cancel the registration event is usually the most common memory leak in .NET. How can we solve this problem automatically? That is to say, when the object to which the method belongs has been marked as garbage, we will unregister this method in the event. This can be done with a weak reference.

The essence of a delegate is a class that contains several key properties:

1. Point to the Target property of the original object (strong reference).

2. A ptr pointer to the method.

3. The internal maintains a collection (delegate is implemented in a linked list structure).

Because the delegate in .NET is a strong reference, we need to change it to a weak reference. We can grab these features and create our own WeakDelegate class.

The essence of an event is an accessor method, and the relationship with the delegate is similar to fields and properties, that is, controlling external access to the field. We can convert external delegates into our own defined delegates by customizing the add and remove methods.

Public  class Button
{
    Private  class WeakDelegate
    {
        Public WeakReference Target;
         public MethodInfo Method;
    }

    Private List<WeakDelegate> clickSubscribers = new List<WeakDelegate> ();

    Public  event EventHandler Click
    {
        Add
        {
            clickSubscribers.Add( new WeakDelegate
            {
                Target = new WeakReference(value.Target),
                Method = value.Method
            });
        }
        Remove
     {
          .....
       }
    }

    Public  void FireClick()
    {
        List <WeakDelegate> toRemove = new List<WeakDelegate> ();
         foreach (WeakDelegate subscriber in clickSubscribers)
        {
       // The first Target represents the object to which the method belongs, the second Target indicates whether the object is marked as garbage, and if it is null, it is marked as garbage. 
            Object target = subscriber.Target.Target;
             if (target == null )
            {
                toRemove.Add(subscriber);
            }
            Else
            {
                subscriber.Method.Invoke(target, new  object [] { this , EventArgs.Empty });
            }
        }
        clickSubscribers.RemoveAll(toRemove);
    }
}

Weak references can also be used to create a pool of objects that manage memory and GC stress by managing a small number of objects. We can use strong references to represent the smallest number of objects in the object pool, and weak references to indicate the maximum number that can be reached.