Several cases of memory overflow

One: event-driven

Cause the event object was not released, or is still referenced

class TestClassHasEvent     
 {     
     public delegate void TestEventHandler(object sender, EventArgs e);     
     public event TestEventHandler YourEvent;     
     protected void OnYourEvent(EventArgs e)     
     {     
         if(YourEvent ! =null) YourEvent(this, e); }}//public TestListener(TestClassHasEvent inject)
/ / {
// SystemEvents.DisplaySettingsChanged += new EventHandler(SystemEvents_DisplaySettingsChanged);
/ /}

//void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
/ / {

/ /}
class TestListener     
 {    
     byte[] m_ExtraMemory = new byte[1000000];    
      
     private TestClassHasEvent _inject;    
      
     public TestListener(TestClassHasEvent inject)    
     {    
         _inject = inject;    
         _inject.YourEvent += new TestClassHasEvent.TestEventHandler(_inject_YourEvent);    
     }    
         
     void _inject_YourEvent(object sender, EventArgs e)    
     {    
             
     }    
 }    
      
 class Program    
 {    
     static void DisplayMemory()    
     {    
         Console.WriteLine("Total memory: {0:###,###,###,##0} bytes", GC.GetTotalMemory(true));    
     }    
      
     static void Main()    
     {    
         DisplayMemory();    
         Console.WriteLine();    
         for (int i = 0; i < 5; i++)    
         {    
             Console.WriteLine("--- New Listener #{0} ---", i + 1);    
      
             var listener = new TestListener(new TestClassHasEvent());    
            listener = null; // OptionalGC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); DisplayMemory(); } Console.Read(); }}Copy the code

The solution

class TestListener : IDisposable     
{     
    byte[] m_ExtraMemory = new byte[1000000];    
      
    private TestClassHasEvent _inject;     
      
    public TestListener(TestClassHasEvent inject)    
    {    
        SystemEvents.DisplaySettingsChanged += new EventHandler(SystemEvents_DisplaySettingsChanged);    
    }    
     
    void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e){}#region IDisposable Members    
     
    public void Dispose()    
     {    
        SystemEvents.DisplaySettingsChanged -= new EventHandler(SystemEvents_DisplaySettingsChanged);    
    }    
     
    #endregion    
}    
     
class Program    
{    
    static void DisplayMemory()    
    {    
         Console.WriteLine("Total memory: {0:###,###,###,##0} bytes", GC.GetTotalMemory(true));    
    }    
     
    static void Main()    
    {    
        DisplayMemory();    
        Console.WriteLine();    
        for (int i = 0; i < 5; i++)    
        {    
             Console.WriteLine("--- New Listener #{0} ---", i + 1);    
                
            using (var listener = new TestListener(new TestClassHasEvent()))    
            {    
                 //do something    } GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); DisplayMemory(); } Console.Read(); }}Copy the code

The above two examples of a memory leak, a memory leak, no I think you should know the reason, the fundamental difference is that the latter has a SystemEvents. DisplaySettingsChanged events, Static Static event, the event was so bound to this event on the object will not be released

// Type: Microsoft.Win32.SystemEvents  
// Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken= b77a5C561934e089
// Assembly location: C: \ Program Files \ Reference Assemblies\Microsoft\Framework\.NET Framework \ v4.0 \ profiles \ Client \ System. DLL
   
 using System;  
 using System.ComponentModel;  
    
 namespace Microsoft.Win32  
 {  
     public sealed class SystemEvents  
     {  
         public static IntPtr CreateTimer(int interval);  
         public static void InvokeOnEventsThread(Delegate method);  
         public static void KillTimer(IntPtr timerId);  
         public static event EventHandler DisplaySettingsChanging;  
         public static event EventHandler DisplaySettingsChanged;  
         public static event EventHandler EventsThreadShutdown;  
         public static event EventHandler InstalledFontsChanged;  
     
         [EditorBrowsable(EditorBrowsableState.Never)]  
         [Obsolete("This event has been deprecated. http://go.microsoft.com/fwlink/?linkid=14202")]  
         [Browsable(false)]  
         public static event EventHandler LowMemory;  
    
         public static event EventHandler PaletteChanged;  
         public static event PowerModeChangedEventHandler PowerModeChanged;  
         public static event SessionEndedEventHandler SessionEnded;  
         public static event SessionEndingEventHandler SessionEnding;  
         public static event SessionSwitchEventHandler SessionSwitch;  
         public static event EventHandler TimeChanged;  
         public static event TimerElapsedEventHandler TimerElapsed;  
         public static event UserPreferenceChangedEventHandler UserPreferenceChanged;  
         public static eventUserPreferenceChangingEventHandler UserPreferenceChanging; }}Copy the code

Note that Static Singleton is a Static object that has a long lifetime and is never collected by the GC. Once referenced by a Singleton, it is impossible to release it. The above example is SystemEvents. DisplaySettingsChanged + = new EventHandler (SystemEvents_DisplaySettingsChanged); It means that this class be SystemEvents. DisplaySettingsChanged quotes, through its function. Another thing to be aware of is the classes implemented by the Singleton Singleton pattern. They are also static and have long life cycles. Note the reference chain, whether your class is referenced by it or not.

There are also events that note objects that are not released during program execution

There is also a case where neither your object is static and cannot be freed, nor is it a Singleton, but instead your object is referenced by an object that will never be freed, which may not be static. For example, if you have a MainForm in your interface, the MainForm will never be closed or released, if it references it, it will never be released. Here’s an example:

MainForm has a public event inside it. Open Form2 and close it to see if Form2 can be released:

public partial class MainForm : Form     
{     
    public event PropertyChangedEventHandler PropertyChanged;     
      
   protected virtual void OnPropertyChanged(string propertyName)     
   {     
        PropertyChangedEventHandler handler = PropertyChanged;     
      
        if(handler ! =null)    
            handler(this.new PropertyChangedEventArgs(propertyName));    
    }    
     
    public MainForm()    
    {    
        InitializeComponent();    
    }    
     
    private void button1_Click(object sender, EventArgs e)    
    {    
        Form2 frm = new Form2();   
     
        this.PropertyChanged += frm.frm_PropertyChanged;     
        //MainForm referenced form2, because main form is not released, therefore form2 will not released.    
     
        DialogResult d = frm.ShowDialog();    
            
        GC.Collect();    
        ShowTotalMemory();    
     
    }    
     
        
    
    private void ShowTotalMemory()    
    {    
        this.listBox1.Items.Add(string.Format("Memory: {0:###,###,###,##0} bytes", GC.GetTotalMemory(true))); }}Copy the code

Form2 has a function in it:

public partial class Form2 : Form     
 {     
     public Form2()     
     {     
         InitializeComponent();     
     }     
     public void frm_PropertyChanged(object sender, PropertyChangedEventArgs e){}}Copy the code

So in this case, if your Event Handler doesn’t log out manually, it’s a memory leak.

Two: unmanaged resources

public partial class MemoryLeak
{
     
    public static void Demo2()
    {

        while (true)
        {
            var x = File.OpenRead($"c:\\audio.log"); }}}Copy the code

Three: thread wait

public partial class MemoryLeak
{
    /// <summary>
    /// https://docs.microsoft.com/zh-cn/previous-versions/dotnet/articles/ms973858(v=msdn.10)?redirectedfrom=MSDN
    /// </summary>

    public static void Demo3(){{while (true)
            { 
                Console.ReadLine();
                Thread t = new Thread(newThreadStart(ThreadProc)); t.Start(); }}}static void ThreadProc(){ Thread.CurrentThread.Join(); }}Copy the code

Four: String

Local assemblies use const, cross-assemblies use readnoly

public partial class MemoryLeak
    { 

        public static void Demo4()
        {
            List<string> asd = new List<string> ();while (true)
            {
                ///String it's not just any heap
                ///.NET has something called a memory resident-->String pool --->String resident pool
                ///Your strings will be stored and will not "exactly" follow GC
                asd.Add(Guid.NewGuid().ToString());
                if (asd.Count > 10000)
                {
                    asd.Clear();
                    Console.WriteLine("asdasdasdasd" + 1);
                    Console.WriteLine("Error info");
                    Console.WriteLine("Error info");
                    Console.WriteLine("error");
                    Console.WriteLine("erorr"); }}}}Copy the code