65.9K
CodeProject 正在变化。 阅读更多。
Home

修复由大型元文件导致的Windows高内存使用率

2023年5月7日

CPOL

3分钟阅读

viewsIcon

3284

修复由大型元文件导致的Windows高内存使用率

安装第三方Windows服务后不久,我的Windows 2008 R2服务器的内存使用率突然上升——从安装的16GB中仅使用了4GB飙升到大部分时间都高达99%,正如任务管理器报告的那样。

task manager full memory

在对进程选项卡进行了详细分析后,该分析未发现任何似乎消耗大量内存的进程,我下载了进程监视器进行检查,并立即注意到一个进程导致了数千个文件系统活动,这些活动试图读取某些数据文件,如下面的屏幕截图所示。

readfile1

使用RAMMap进行进一步调查显示,元文件大小非常大。

high metafile size

此时,高内存使用率可以归因于有问题的进程,该进程在读取/写入数据文件时创建许多文件句柄,或许在完成操作后没有适当地关闭文件句柄。这导致元文件的大小增加,而元文件需要跟踪文件系统活动。由于元文件缓存由不同的进程共享,因此任务管理器报告的有问题的进程的内存使用率仍然很低,因为任务管理器在计算进程内存使用率时没有考虑元文件的大小。

起初,我尝试重新启动有问题的应用程序,导致内存消耗立即下降。但是,由于应用程序中的错误导致内存泄漏,服务器的内存消耗在三天多一点的时间内又很快上升到99%。我下载并安装了微软的动态缓存服务,希望一些缓存可以帮助防止内存泄漏。但是,令我失望的是,虽然动态缓存服务有所帮助,但泄漏非常严重,应用程序运行两周后,内存消耗最终又会增加到99%以上。安排任务每天重新启动应用程序可以帮助减少内存使用,但也可能导致服务中断。所以我肯定需要一个更永久的解决方案。

接下来,我尝试了RAMMap的清空菜单中的“清空工作集”和“清空系统工作集”,并注意到内存使用率立即下降,而无需重新启动服务。

empty working set

清空集合后,服务仍然正常工作。所以至少这是一个不错的解决方法。我的下一个任务是编写一个程序来自动清空集合,并在等待制造商提供官方修复程序的同时将其作为计划任务运行。为此,我使用了Analysis Services存储过程项目中的代码,该项目有一个包装方法可以清除文件系统缓存。

FileSystemCache.ClearAllCaches();

但是,事实证明,此清理不如RAMMap彻底,您仍然需要使用以下代码手动清空每个进程的工作集才能获得相同的效果。

static void Main(string[] args)
{
  try
  {
    Console.WriteLine("Clearing active/standby system file cache ...");
    FileSystemCache.ClearAllCaches();
    Console.WriteLine("Successfully cleared active/standby system file cache ...");
  }
  catch (Exception ex)
  {
    Console.Write(ex.Message);
  }

  Process[] plist = Process.GetProcesses();
  try
  {
    foreach (Process p in plist)
    {
      if (p.Id == Process.GetCurrentProcess().Id)
      {
        Console.WriteLine("Ignoring current process #" + 
                           p.Id + " (" + p.ProcessName + ")");
      }
      else
      {
        Console.WriteLine("Emptying working set for process #" + 
                           p.Id + " (" + p.ProcessName + ")");
        EmptyWorkingSet(p.Handle.ToInt64());
        Console.WriteLine("Successfully emptied working set for process #" + 
                           p.Id + " (" + p.ProcessName + ")");
      }
    }
  }
  catch (Exception ex)
  {
    Console.WriteLine("Error: " + ex.Message);
  }
}

[DllImport("psapi")]
public static extern bool EmptyWorkingSet(long hProcess);

包含已编译可执行文件的完整源代码可以从此处下载。我已经从Analysis Services存储过程项目中删除了不必要的.NET 4.0引用,以使可执行文件与.NET 2.0兼容。请注意,程序需要以管理员身份运行才能正常工作。

© . All rights reserved.