防止繁重的进程陷入交换文件中
-
08-07-2019 - |
题
我们的服务往往会在晚上在客户的服务器上睡着,然后很难醒来。似乎发生的情况是,进程堆(有时有数百 MB)被移动到交换文件中。这种情况发生在晚上,当我们的服务未使用时,其他服务计划运行(数据库备份、AV 扫描等)。发生这种情况时,在几个小时不活动后,对服务的第一次调用最多需要几分钟(后续调用需要几秒钟)。
我很确定这是虚拟内存管理的问题,而且我真的很讨厌强制操作系统将我们的服务保留在物理内存中的想法。我知道这样做会损害服务器上的其他进程,并降低服务器的整体吞吐量。话虽如此,我们的客户只是希望我们的应用程序能够响应。他们不在乎夜间工作是否需要更长的时间。
我依稀记得有一种方法可以强制 Windows 将页面保留在物理内存上,但我真的很讨厌这个想法。我更倾向于一些内部或外部看门狗,它们将启动更高级别的功能(已经有一些内部调度程序做得很少,并且没有区别)。如果有一个第三方工具提供这种服务那就太好了。
我很想听到任何评论、建议和此类问题的常见解决方案。该服务采用VC2005编写,运行在Windows服务器上。
解决方案
正如您所提到的,强制应用程序保留在内存中并不是在计算机上共享资源的最佳方式。您可能会发现效果很好的快速解决方案是在客户开始使用之前,每天早上安排一个在特定时间唤醒服务的事件。您可以使用简单的脚本或EXE调用在Windows任务计划程序中安排它。
其他提示
我不是说你想要做到这一点,或者说这是最好的做法,但你可能会发现它对你来说效果很好。它似乎符合您的要求。
摘要:定期触摸流程中的每个页面,一次一页。
如何在后台运行并每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))来避免异常处理程序,因为应用程序中的其他线程可能同时修改内存保护。如果因为这个原因而失败,几乎不可能确定原因(很可能是不可重复的竞争条件),所以不要浪费时间。
当然,您希望在白天关闭此线程,并且只在死区时间运行它。
第三种方法可能是让你的服务运行一个线程,它做一些微不足道的事情,比如递增一个计数器,然后睡一段相当长的时间,比如10秒。 Thios对其他应用程序的影响应该很小,但至少保留一些页面可用。
另一件要确保的事情是您的数据是本地化的。
换句话说:您真的需要全部 300 MiB 内存才能执行任何操作吗?您使用的数据结构是否可以重新排列,以便仅用几兆字节即可满足任何特定请求?
例如
如果您的 300 MiB 堆内存包含面部识别数据。内部可以安排数据,让男女人脸数据存储在一起吗?或者大鼻子和小鼻子是分开的?
如果它具有某种逻辑结构,可以对其进行排序吗?以便可以使用二分搜索来跳过很多页面?
如果它是专有的内存数据库引擎,是否可以更好地对数据进行索引/聚集,以便不需要这么多的内存页面点击?
如果它们是图像纹理,常用的纹理可以彼此靠近吗?
您真的需要全部 300 MiB 内存才能执行任何操作吗?如果没有,您就无法请求服务 全部 该数据回到内存中?
否则: 计划任务在 6 点唤醒它。
就成本而言,最便宜和最简单的解决方案可能只是为该服务器购买更多RAM,然后您可以完全禁用页面文件。如果您正在运行32位Windows,只需购买4GB内存。然后整个地址空间将使用物理内存进行备份,并且页面文件无论如何都不会执行任何操作。