C#WPF内存回收与释放LierdaCracker

本文介绍了WPF程序常出现内存占用过高的问题,并提出使用LierdaCracker进行内存管理的解决方案。LierdaCracker结合GC垃圾回收机制和系统API SetProcessWorkingSetSize来尝试释放内存。通过在Application_Startup中实例化并调用,或者自定义实现类,定期执行内存清理。尽管这种方法可能会导致性能影响,但在某些场景下能有效缓解内存压力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用wpf程序常常会出现一个问题,那就是内存占用过高,使用wpf的程序功能越复杂往往用着用着内存就本着90往上去了。

一方面wpf本身是一个ui框架,对图像以及界面的渲染虽然提高了软件的美观性,但实际使用过程中调用和消耗了大量的内存来进行协同处理;
另一方面这些调用的内存的确在使用完成之后并没有进行主动的释放或者是只是自动释放了一部分,即对于托管资源通过GC自动清理回收。对于非托管资源,通过代码调用手动进行清除,再由GC回收。例如流,数据库连接,网络连接等,所以就需要我们主动定时的对内存进行回收释放的处理。

在这里非常推荐使用LierdaCracker

一.可以使用nuget管理安装Lierda.WPFHelper包,在项目的App.xaml.cs中的Application_Startup方法里实例化并调用cracker方法直接使用

   LierdaCracker cracker = new LierdaCracker();
   cracker.Cracker();

二.自己实现LierdaCracker类
提到C#资源和内存回收肯定少不了GC垃圾回收机制,托管堆上的内存由GC全权负责, 值引用的在栈上的内存会随着栈空间的消亡而自动消失。

GC.Collect(); 
GC.WaitForPendingFinalizers();

此方法强制对所有代进行即时垃圾回收!
当应用程序代码中某个确定的点上使用的内存量大量减少时,在这种情况下使用 GC.Collect 方法可能比较合适。而GC.WaitForPendingFinalizers则是提供收集完成前的等待。

另外一个非常重要的系统api在释放内存的时候也是非常重要的
SetProcessWorkingSetSize,使用这个函数来设置应用程序最小和最大的运行空间,只会保留需要的内存。当应用程序被闲置或系统内存太低时,操作系统会自动调用这个机制来设置应用程序的内存。应用程序也可以使用 VirtualLock 来锁住一定范围的内存不被系统释放。

事实上,使用该函数并不能提高什么性能,也不会真的节省内存。
因为他只是暂时的将应用程序占用的内存移至虚拟内存,一旦,应用程序被激活或者有操作请求时,这些内存又会被重新占用。如果你强制使用该方法来 设置程序占用的内存,那么可能在一定程度上反而会降低系统性能,因为系统需要频繁的进行内存和硬盘间的页面交换。

BOOL SetProcessWorkingSetSize(
HANDLE hProcess,
SIZE_T dwMinimumWorkingSetSize,
SIZE_T dwMaximumWorkingSetSize
);

将 2个 SIZE_T 参数设置为 -1 ,即可以使进程使用的内存交换到虚拟内存,只保留一小部分代码,它是windowsNT的api 所以使用的使用需要加上平台条件。

 if (Environment.OSVersion.Platform == PlatformID.Win32NT)
  SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, -1, -1);

综合下来LierdaCracker类为

 public class LierdaCracker
 {
	 [DllImport("kernel32.dll")]
     private static extern bool SetProcessWorkingSetSize(IntPtr proc, int min, int max);

	 private void FlushMemory()
     {
          GC.Collect();
          GC.WaitForPendingFinalizers();
          if (Environment.OSVersion.Platform == PlatformID.Win32NT)
              SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, -1, -1);
      }

	  public void Cracker(int sleepSpan = 50)
      {
           _ = Task.Factory.StartNew(delegate
           {
               while (true)
               {
                   try
                   {
                       //SetDate();
                       FlushMemory();
                       Thread.Sleep(TimeSpan.FromSeconds((double)sleepSpan));
                   }
                   catch { }
               }
           });
       }

 }

以上资料有个人累积,也有前辈们总结出来的经验,欢迎指教。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MasterRyan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值