C#内存释放(垃圾回收)

问题背景----html

今天写了个很小的程序,程序的功能仅仅是截图,可是若是长时间开启并截图的时候,程序会变的很大,从刚开始的运行在任务管理器中只有十几K大小,运行一段时间后在任务管理器中看到程序能够达到1G或2G甚至更大;最初想到的是全部的截图都保存在内存中,没有释放形成的。去检查代码,发现程序中已经使用GC.Collect();可是为何程序仍是会一直增长呢?因为程序中逻辑判断等比较多,不方便跟踪及查找。因此我本身单独写了个测试程序,去看看调用GC.Collect();释放的问题?网络

测试环境----并发

首先准备一个对象(因为程序中使用了一些静态变量),因此准备的对象以下:模块化

public class CountObject
    {
        public static int Count = 0;
        public CountObject()
        {
            Count++;
        }

        ~CountObject()
        {
            Count--;
        }
    }

程序很简单,只有一个静态的计数变量。下面在看看主程序:性能

 1 static void Main(string[] args)
 2         {
 3             CountObject obj;
 4             for (int i = 0; i < 5; i++)
 5             {
 6                 obj = new CountObject();
 7                 //obj = null; // 这一步,只是为了更清晰些验证引用的对象是否释放!
 8                 GC.Collect();
 9 
10             }
11             //GC.Collect();
12             //GC.WaitForPendingFinalizers();
13 
14             // Count不会是1,由于Finalizer不会立刻被触发,要等到有一次回收操做(GC.Collect())后才会被触发。 GC.Collect();GC.WaitForPendingFinalizers();
15             Console.WriteLine(CountObject.Count);
16             Console.ReadKey();
17         }

程序也比较简单,我作了以下测试:测试

1)使用以上程序运行,发现15行会输出5,说明咱们调用了GC.Collect();但程序并无执行释放,由于查GC的官方解释,是不肯定的某个时刻进行回收。优化

2)把循环每次增大5个。当循环增长到125的时候,屡次执行后发现,我本机测试,在第15行的输出是1或125,当增长到10000,每次都输出1,说明符合官方解释;this

根据以上代码测试知道,当循环5次的时候,GC并不会当即执行,因此当执行5次循环的时候第8行没起做用。既然不起做用,咱们把他注释暂时不用,把11和12行开启。spa

3)把地8行注释,11,12行开启,执行5次循环,发现15行输出1,屡次执行结果相同。.net

4)再把11行注释,12行开启,执行5次循环,发现15行输出5,屡次执行结果相同。

5)再把12行注释,11行开启,执行5次循环,发现15行输出5,屡次执行结果相同。

根据4和5的才测试能够看到,当少许的循环时Finalizer不会立刻被触发,要等到有一次回收操做(GC.Collect())执行后才会被触发。因此咱们能够显式调用 GC.Collect();GC.WaitForPendingFinalizers();这两行代码进行强制回收的执行。

6)验证,把第7行开启,执行测试第15行为0,说明对象若是没有任何的引用则能够强制回收。

以上是本人的一些测试,若是你还有更好的想法,能够提出一块儿讨论;

版权归我的全部,转载请注明出处;

 


 

由内存释放致使的问题:

软件在测试力度加大状况下,可能致使的内存不足及崩溃的问题可能快速暴露,针对这些问题能够经过下面方式解决,欢迎补充。
1. 经常使用方式:
A)类文件中占用内存较大的全局变量,公共变量,类私有变量及类的实例用完以后手动设置为null或Dispose(),对局部变量不须要置null,但局部的实例须要Dispose或置null。
B)占用内存较大的变量或实例,在循环建立这些类或实例的地方适当进行置null或Dispose()后进行GC.Collect();
 
2. 结合代码业务进行代码重构:
A) 将主程序中的功能模块化,如封装到动态库中后,经过订阅的方式再也不进行主动的业务请求,下降主进程负担。
B) 对程序中会频繁重复使用的类如心跳,网络监控和弹出窗体,历史信息类等,避免重复实例化,经过定义全局惟一静态变量的方式即单例模式实现循环使用。
C) 优化代码或重构
 
结论,一般合理使用方式1基本能够解决大部份内存不足致使的崩溃问题,但垃圾回收有时效性等底层判断机制,主动垃圾回收对于内存快速消耗的状况可能效果很差(好比进行1秒百万级,或者只须要几千个并发,在置null和GC以前程序就已经死掉,即垃圾回收不能根本解决程序内存消耗和性能问题,须要不产生垃圾或少产生垃圾),若是对程序性能和质量有更好的要求,结合两种方式使用。
 
举例:

1.public void Dispose()
   {
        GC.Collect();
        GC.SuppressFinalize(this);
   }

2.线程终止及清理

          _thread.Abort();
          _thread.DisableComObjectEagerCleanup();
          _thread = null;

3.更完全的垃圾回收

    /// <summary>
    ///设置线程工做的空间
    /// </summary>
    /// <param name="process">线程</param>
    /// <param name="minSize">最小空间</param>
    /// <param name="maxSize">最大空间</param>
    /// <returns></returns>
    [DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize")]
    public static extern int SetProcessWorkingSetSize(IntPtr process, int minSize, int maxSize);
    /// <summary>      
    /// 释放内存      
    /// </summary>      
    public static void ClearMemory()
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();
        if (Environment.OSVersion.Platform == PlatformID.Win32NT)
        {
            SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
        }
    }

4.代码重构太宽泛,自行总结

出处:https://blog.csdn.net/jiandanji123/article/details/79416398

==========================================================

C#如何当即回收内存

=

1.把对象赋值为null

2.当即调用GC.Collect();
 
注意:这个也只是强制垃圾回收器去回收,但具体何时执行不肯定。 
 
代码:
  public partial class Form1 : Form
    {
        [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize", ExactSpelling = true, CharSet =System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true)]
        private static extern int SetProcessWorkingSetSize(IntPtr process, int minimumWorkingSetSize, int maximumWorkingSetSize);
 
 
        public Form1()
        {
            InitializeComponent();
        }
 
 
        private void button1_Click(object sender, EventArgs e)
        {
            ClearMemory();
        }
 
 
        #region 内存回收
   public  void ClearMemory()
 {
     GC.Collect();
     GC.SuppressFinalize(this);
 
 
     if (Environment.OSVersion.Platform == PlatformID.Win32NT)
     {
         SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
     }
 }
 #endregion
 
 
   private void timer1_Tick(object sender, EventArgs e)
   {
       string s="clearMemory";
       Form dt = new Form();
       dt.Text = s;
       //若是垃圾产生于timer中可能没法马上回收资源,需加载timer tick事件中,马上回收资源,或使用另外的timer控制回收时间。
       GC.Collect();
   }
 
}
[System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize", ExactSpelling = true, CharSet =System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true)]
        private static extern int SetProcessWorkingSetSize(IntPtr process, int minimumWorkingSetSize, int maximumWorkingSetSize);

 #region 内存回收
   public  void ClearMemory()
 {
     GC.Collect();
     GC.SuppressFinalize(this);
 
 
     if (Environment.OSVersion.Platform == PlatformID.Win32NT)
     {
         SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
     }
 }
 #endregion

ClearMemory();

 

=

出处:https://blog.csdn.net/xwnxwn/article/details/78009071

http://www.javashuo.com/article/p-mrpvvqvo-dd.html

相关文章
相关标签/搜索