防止繁重的进程在交换文件中下沉

时间:2009-05-07 08:36:52

标签: windows performance virtual-memory pagefile

我们的服务往往在客户服务器的夜晚入睡,然后很难醒来。似乎发生的事情是进程堆(有时几百MB)被移动到交换文件中。这种情况发生在晚上,当我们的服务没有使用时,其他人计划运行(数据库备份,AV扫描等)。发生这种情况时,经过几个小时的不活动后,第一次拨打该服务需要几分钟(后续通话需要几秒钟)。

我很确定这是一个虚拟内存管理问题,我真的很讨厌强迫操作系统将我们的服务保留在物理内存中。我知道这样做会损害服务器上的其他进程,并降低整体服务器吞吐量。话虽如此,我们的客户只是想让我们的应用程序响应。他们不关心夜间工作需要更长的时间。

我依旧记得有一种方法可以强制Windows将页面保留在物理内存上,但我真的很讨厌这个想法。我更倾向于一些内部或外部监视器,它将启动更高级别的功能(已经有一些内部调度程序做得很少,没有任何区别)。如果有第三方工具提供了那种服务就好了。

我很想听到有关此类问题的任何意见,建议和常见解决方案。该服务使用VC2005编写,可在Windows服务器上运行。

5 个答案:

答案 0 :(得分:8)

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

答案 1 :(得分: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))来避免异常处理程序,因为应用程序中的其他线程可能同时修改内存保护。如果因为这个原因而失败,几乎不可能确定原因(很可能是不可重复的竞争条件),所以不要浪费时间。

当然,您希望在白天关闭此线程,并且只在死区时间运行它。

答案 2 :(得分:1)

第三种方法可能是让你的服务运行一个线程,它做一些微不足道的事情,比如递增一个计数器,然后睡一段相当长的时间,比如10秒。 Thios对其他应用程序的影响应该很小,但至少保留一些页面可用。

答案 3 :(得分:1)

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

换句话说:在你做任何事之前,你真的需要所有300 MiB的内存吗?您可以重新安排您使用的数据结构,以便只需几兆字节即可满足任何特定请求吗?

例如

  • 如果您的300 MiB堆内存包含面部识别数据。可以在内部安排数据,以便将男性和女性面部数据存储在一起吗?或者大噪声与小鼻子分开?

  • 如果它有某种逻辑结构,它可以排序吗?这样二元搜索可以用来跳过很多页面吗?

  • 如果它是一个支持内存的数据库引擎,数据可以更好地索引/聚类到不需要这么多内存页面命中吗?

  • 如果它们是图像纹理,常用的纹理可以位于彼此附近吗?

在你做任何事情之前,你真的需要所有300 MiB的内存吗?如果不将所有数据重新存储在内存中,您就无法提供服务请求吗?


否则: 6点的预定任务将其唤醒。

答案 4 :(得分:0)

就成本而言,最便宜和最简单的解决方案可能只是为该服务器购买更多RAM,然后您可以完全禁用页面文件。如果您正在运行32位Windows,只需购买4GB内存。然后整个地址空间将使用物理内存进行备份,并且页面文件无论如何都不会执行任何操作。