7

是否有类似批处理命令或强制Windows缓存该文件的东西?我正在尝试创建一个游戏预加载器,在开始游戏之前将某些游戏文件加载到缓存中。有什么办法可以做到这一点吗?

更新 int 主要代码:

int main(int argc, const char** argv)
{
if(argc >= 2) for(int i = 1; argv[i]; ++i) pf("C:\\Games\World_of_Tanks\res\packages\gui.pkg"[i]);
return 0;
}
4

1 回答 1

15

您需要做的就是加载文件,使用ReadFile或通过内存映射文件并触摸每一页(事实上,由于分配粒度每 16 页就足够了,但理论上您应该触摸每一页)。
内存映射更快且对缓存更友好,因为您不需要分配额外的内存来保存数据(您不会将其用于任何有用的事情!)。操作系统将为缓存和您的进程可以看到的虚拟内存重用相同的物理内存。

包括 Microsoft Office 和 Adob​​e Reader 在内的一些主流应用程序正是这样做的,以加快启动速度。正是这些“延迟启动”服务在您登录后让您的硬盘灯闪烁十几秒钟。

但是请注意,虽然您可以强制 Windows 1以这种方式缓存文件,但不能强制它无限期地将文件保留在缓存中。如果没有足够的物理 RAM 可用,系统将丢弃缓存内容以满足应用程序需求。

编辑:使用文件映射的最小工作示例实现:

#include <windows.h>
#include <cstdio>

void pf(const char* name)
{
    HANDLE file = CreateFile(name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    if(file == INVALID_HANDLE_VALUE) { printf("couldn't open %s\n", name); return; };

    unsigned int len  = GetFileSize(file, 0);

    HANDLE mapping  = CreateFileMapping(file, 0, PAGE_READONLY, 0, 0, 0);
    if(mapping == 0) { printf("couldn't map %s\n", name); return; }

    const char* data = (const char*) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);

    if(data)
    {
        printf("prefetching %s... ", name);

        // need volatile or need to use result - compiler will otherwise optimize out whole loop
        volatile unsigned int touch = 0;

        for(unsigned int i = 0; i < len; i += 4096)
            touch += data[i];
    }
    else
        printf("couldn't create view of %s\n", name);

    UnmapViewOfFile(data);
    CloseHandle(mapping);
    CloseHandle(file);
}

int main(int argc, const char** argv)
{
    if(argc >= 2) for(int i = 1; argv[i]; ++i) pf(argv[i]);
    return 0;
}

该程序将尝试预取命令行上给出的任何文件名。
该代码并不过分漂亮,但它可以工作。它使用 ANSI 文件名,并在打开成功但映射失败的情况下泄漏文件句柄(但是 bleh ......这不是一个真正的问题,操作系统将在程序退出后清理 - 如果这让你烦恼,请将句柄包装在 RAII 中)。它也仅限于大约。由于 32 位构建中的地址空间,文件大小为 1.8GiB,否则限制为 4GiB GetFileSize,但如果您真的需要那么大的文件,这也很容易修复。
而不是volatile一个人可能想要返回或以其他方式消耗“结果”,但任何一种方式都有效(volatile与磁盘访问相比,并没有真正对性能产生可衡量的影响!)。


1说实话,您实际上无法强制使用 Windows,但顺便说一句,除非您明确请求无缓冲 I/O,否则它总是以这种方式工作。
从理论上讲,您可以强制操作系统将页面读入内存,甚至通过锁定内存来强制将它们保留在 RAM 中,但是您的工作集配额(非常小,您需要管理权限来修改它)通常不会让你这样做。不过这是一件好事,因为锁定大量内存是一个非常糟糕的主意。

于 2013-11-07T01:16:05.307 回答