防止一个耗费大量资源的进程沉没在交换文件中

6
我们的服务在客户的服务器上夜间经常进入睡眠状态,然后很难唤醒。似乎发生的情况是,进程堆栈(有时几百兆字节)被移动到交换文件中。这种情况通常发生在晚上,当我们的服务没有使用时,其他任务被调度(如数据库备份、杀毒扫描等)。这种情况发生后,服务在几个小时的不活动后,第一次调用需要几分钟(随后的调用只需几秒钟)。
我相信这是虚拟内存管理的问题,但我真的不想强制操作系统将我们的服务保留在物理内存中。我知道这样做会影响服务器上的其他进程,并降低整体服务器吞吐量。话虽如此,我们的客户只希望我们的应用程序能够快速响应。他们并不在意夜间作业所需的时间是否更长。
我模糊地记得有一种方法可以强制Windows将页面保留在物理内存中,但我真的不喜欢这个想法。我更倾向于使用一些内部或外部看门狗来启动更高级别的功能(已经有一些内部调度程序,但几乎没有任何作用)。如果有第三方工具提供这种服务,那就更好了。
我很乐意听取任何评论、建议和常见的解决方案。该服务是使用VC2005编写的,并在Windows服务器上运行。
5个回答

8

正如您所提到的,强制应用程序保持在内存中并不是在计算机上共享资源的最佳方式。一个可能会很好地运作的快速解决方案是,在每天早晨客户端开始使用之前,安排一个定时事件来唤醒您的服务。您可以使用简单的脚本或EXE调用在Windows任务计划程序中进行安排。


2
我不是说你想这样做,或者这是最佳实践,但你可能会发现它对你来说足够好用。它似乎符合你所要求的。
总结:在流程中逐页触摸每个页面,并定期执行。
那么,一个后台线程每隔N秒钟唤醒一次怎么样?每次页面唤醒时,它尝试从地址X读取。如果你读取了错误的地址,则使用异常处理程序进行保护。然后将X增加一页的大小。
4GB中有65536页,3GB中有49152页,2GB中有32768页。将空闲时间(过夜死时间)除以您希望(尝试)击中每个页面的频率。
BYTE *ptr;

ptr = NULL;
while(TRUE)
{
    __try
    {
        BYTE b;

        b = *ptr;
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
        // ignore, some pages won't be accessible
    }

    ptr += sizeofVMPage;

    Sleep(N * 1000);
}

您可以从GetSystemInfo()返回的dwPageSize值中获取sizeOfVMPage的值。

不要尝试使用if (!IsBadReadPtr(ptr))来避免异常处理程序,因为应用程序中的其他线程可能同时修改内存保护。如果因此卡住了,几乎不可能确定原因(最有可能是不可重复的竞争条件),所以不要浪费时间。

当然,您希望在白天关闭该线程,并仅在您的空闲时间运行它。


1

另一件要确保的事情是您的数据本地化。

换句话说:在您执行任何操作之前,您真的需要全部 300 MiB 的内存吗?您使用的数据结构是否可以重新排列,以便可以仅使用少量兆字节满足任何特定请求?

例如:

  • 如果您的 300 MiB 堆内存包含面部识别数据。数据是否可以在内部排列,使男性和女性面部数据存储在一起?或者大鼻子与小鼻子分开呢?

  • 如果它具有某种逻辑结构,是否可以对其进行排序?这样就可以使用二进制搜索跳过许多页面了吗?

  • 如果它是专有的内存数据库引擎,是否可以更好地索引/聚集数据,以不需要那么多内存页面命中?

  • 如果它们是图像纹理,常用的纹理是否可以靠近彼此?

在执行任何操作之前,您真的需要全部 300 MiB 的内存吗?没有全部数据返回到内存中,您无法提供服务吗?


否则:在早上 6 点安排任务来唤醒它。


1
第三种方法可能是让您的服务运行一个线程,执行一些微不足道的操作,比如递增计数器,然后休眠一段相当长的时间,比如10秒。这应该对其他应用程序的影响最小,但至少可以保持一些页面可用。

我认为这将使包含此代码片段的页面保留在内存中,但堆仍将被交换。由于堆使用的内存要多得多,问题可能出在它的部分。我可以遍历堆而不是递增计数器,但那不会有最小的影响... - Eran

0
从成本角度来看,最便宜和最简单的解决方案可能就是为该服务器购买更多的RAM,然后您可以完全禁用页面文件。如果您正在运行32位Windows,请购买4GB的RAM。然后整个地址空间将由物理内存支持,而页面文件将不会起到任何作用。

如果只有我的服务在服务器上运行,那就没错了。然而,它还运行着一个Web服务器、一个数据库、一个杀毒软件和其他服务。要消除页面文件的需要,每个进程将需要4GB,是吗?话虽如此,增加更多的RAM是一个好的解决方案,但这取决于客户,我正在寻找一次性开发工作,不会迫使许多客户花费更多的钱。 - Eran
“消除页面文件的需求需要每个进程4GB,是吗?” 据我所知并非如此。对于32位Windows系统而言,4GB是所有内容的总和,如果你能获得全部4GB已经算是很幸运了。例如,这台机器有4GB物理内存,但只有2.75GB可供程序使用,因为其他东西占用了地址空间。” - kquinn
1
但是每个进程都有自己的4GB地址空间(不包括内核占用的部分),因此如果您有30个进程,每个进程都可以使用1GB的RAM,并将大部分内容交换出去,这种情况下仍然需要页面文件... - Steven Schlansker
不建议禁用页面文件,这是个坏主意,因为当系统本应将数据写入页面文件时,禁用页面文件只会导致进程被终止。只需添加更多的RAM即可帮助保持更多的工作集在RAM中。 - nobody

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接