内存映射文件与内存消耗

4

假设有以下测试代码(x64环境):

    static void Test()
    {
        string fileName = @"d:\map";
        long length = new FileInfo(fileName).Length;
        using (var file = MemoryMappedFile.CreateFromFile(fileName, FileMode.Open, "mapFile", length, MemoryMappedFileAccess.ReadWrite))
        {
            byte* bytePtr = (byte*)0;
            var view = file.CreateViewAccessor(0, length, MemoryMappedFileAccess.ReadWrite);
            view.SafeMemoryMappedViewHandle.AcquirePointer(ref bytePtr);

            long count = (long)(length / sizeof(int));
            long sum = 0;
            long step =  count / 2000;

            int* ptr = (int*)&bytePtr[0];
            long currentCount = 0 ;

            Parallel.For(0, count, new ParallelOptions { MaxDegreeOfParallelism = 8 }, (i) =>
            {
                Interlocked.Add(ref sum, ptr[i]);
                Interlocked.Increment(ref currentCount) ;

                if (currentCount % step == 0)
                    Console.Write("\r{0:0.00}%", (100 * currentCount / (float)count));
            });

            Console.WriteLine(sum);

            view.Dispose();
        }
    }

考虑到"d:\map"是一个40GB的文件,在通过指针"ptr"随机访问时,会出现非常奇怪的行为。系统物理内存被完全使用,一切都变得缓慢,该过程需要超过2个小时才能完成。
当我进行顺序(单线程)访问时,使用的物理内存不超过1GB,该进程大约需要8分钟。
我的问题是:使用内存映射文件时,是否使用“真实”的内存?难道不仅仅是占用虚拟地址空间吗?
我正在尝试了解使用内存映射文件时的物理内存消耗情况。
1个回答

7

内存映射文件使用虚拟内存。在64位操作系统上,您可以轻松地将多个千兆字节的虚拟内存空间映射到RAM大小之外。需求分页虚拟内存操作系统的目的是,所有运行进程所需的内存总和始终大于RAM的总量。

将其映射到RAM会产生成本,这就是需求发挥作用的地方。当程序尝试访问未映射到RAM的虚拟内存地址时,处理器会中断程序并寻求帮助。这就是所谓的页面错误。

如果您没有花费足够的资金来获取至少40GB的RAM,则必然要为处理这些页面错误的操作系统付出成本。需要分配一个RAM页面并将其填充为文件的内容。当它必须取消映射先前映射的RAM并将其内容保存到文件时,性能会下降。随后重新使用释放的RAM页面,并从适当的文件偏移加载文件内容。磁盘速度很慢,这就是所谓的“抖动”问题。

当您按顺序访问内存时,这个问题就不那么重要了。对于4096字节的连续访问,一个页面错误是很好的。您有很大几率在触发页面错误时磁盘读取头仍然在正确的位置。


我是否正确地理解,我可以将真正巨大的1-2Gb文件映射到我的进程中,并且这些内存将从虚拟内存中获取?但是,这是否意味着我的进程将消耗1-2 Gb的内存? - Vlad

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