c++ - 在Windows上打开文件的内存开销是多少?

标签 c++ windows winapi file-io createfile

TL; DR

在现代Windows系统上打开文件需要占用多少内存?某些应用程序负载将需要打开“大量”文件。 Windows非常有能力打开“大量”文件,但是保持单个文件打开的负担是什么,以便人们可以确定何时“大量”是“太多”?

背景

为了在32位进程中顺序处理大型数据集(100s MB〜几GB),我们需要提供一个缓冲区,将其内容存储在磁盘上而不是内存中。

我们已经充实了一点类(class),没有太多问题(将CreateFileFILE_ATTRIBUTE_TEMPORARYFILE_FLAG_DELETE_ON_CLOSE一起使用)。

问题是,这些缓冲区的使用方式使得每个缓冲区(每个临时文件)都可能存储从几个字节到几GB的数据,并且我们希望将缓冲区类本身保持在最小限度并尽可能一般的尽可能。

用例的范围从100个缓冲区(每个缓冲区约100MB)到100.000s缓冲区(每个缓冲区仅几个字节)。 (是的,从这个意义上讲,每个缓冲区都有自己的文件很重要。)

在缓冲区类中包含一个缓冲区阈值似乎很自然,该缓冲区阈值仅在其实际存储的字节数超过创建和引用临时文件所用(内存)开销的字节数时才开始创建和使用临时磁盘文件。以及物理机内存上的负载。

问题

在现代Windows系统上,打开(临时)文件需要多少字节的内存?

  • CreateFileFILE_ATTRIBUTE_TEMPORARYFILE_FLAG_DELETE_ON_CLOSE一起使用
  • 打开文件
  • 的(32位)进程的虚拟地址空间的字节
  • 计算机上物理内存的字节数(包括任何内核数据结构)

  • 也就是说,当您开始看到通过将数据存储在文件中而不是内存中而获得净主内存 yield (过程中以及物理上)时,阈值(以字节为单位)是多少?

    笔记:

    提到的open file limit注释不适用于CreateFile,仅适用于MS CRT文件API。 (通过CreateFile打开10.00s的文件在我的系统上根本没有问题-是否一个好主意完全是另一回事,而不是这个问题的一部分。

    内存映射文件:完全不适合在32位进程中处理GB的数据,因为您不能可靠地将如此大的数据集映射到32位进程的正常2GB地址范围内。对于我的问题是完全没有用的,并且根本不与实际问题相关。普通文件仅适合解决背景问题。

    看了http://blogs.technet.com/b/markrussinovich/archive/2009/09/29/3283844.aspx-它告诉我HANDLE本身在64位系统上占用16个字节,但这仅是句柄。

    查看了STXXL及其文档,但是此lib既不适合我的任务,也没有在开始实际使用文件之前发现任何有用的阈值。

    有用的评论摘要:

    Raymond writes:“答案将取决于所安装的防病毒软件的不同,因此唯一的了解方法是在生产配置上对其进行测试。”

    qwm writes:“我会更关心cpu开销。无论如何,回答您的问题的最好方法是对其进行测试。我只能说_FILE_OBJECT的大小(包括_OBJECT_HEADER)约为300b,其中某些字段是指向其他相关结构的指针。”

    Damon wri tes:“一个正确的答案是:10字节(在我的Windows 7机器上)。由于没有其他人似乎值得实际尝试,所以我做了(测得的MEMORYSTATUSEX::ullAvailVirtual差异超过10万次调用,其他都没有运行。)我不知道为什么它不是8或16字节,占用了大约17秒的内核时间,退出时进程打开了100,030个句柄,运行期间专用工作集增加了412k,而全局可用VM减少了1M ,因此大约60%的内存开销都在内核内部。(...)“

    “更令人震惊的是CreateFile显然消耗了大量的内核时间(这是CPU时间,而不是等待磁盘!)​​。10万次调用的17秒分解为打开该计算机上一个句柄的时间大约为450,000个周期。相比之下,仅有的10个字节的虚拟内存丢失就可以忽略不计了。”

    最佳答案

    我现在进行了一些测量:

  • 我设置了2G的RAM磁盘,以免弄乱我的普通NTFS文件表。
  • 我循环创建了1M个文件(1,000,000个),并通过perfmon检查了各种系统性能指标。

  • 创建一个临时文件的调用(直到结束时我一直保持它的句柄)如下所示:
    HANDLE CreateNewTempFile(LPCTSTR filePath) {
        return ::CreateFile(
            filePath, 
            GENERIC_READ | GENERIC_WRITE, // reading and writing
            FILE_SHARE_READ, // Note: FILE_FLAG_DELETE_ON_CLOSE will also block readers, unless they specify FILE_SHARE_DELETE 
            /*Security:*/NULL, 
            CREATE_NEW, // only create if does not exist
            FILE_ATTRIBUTE_TEMPORARY | // optimize access for temporary file
            FILE_FLAG_DELETE_ON_CLOSE, // delete once the last handle has been closed
            NULL);
    }
    

    结果是:
  • 再次删除所有临时文件后,RAM磁盘使用情况如下:
  • 总计2060 M字节
  • 已使用1063 M字节
  • 释放997 M字节
  • 比较开始和结束值(之间有一些样本)我得出以下结论:每个打开的(临时)文件的平均内存消耗如下:
  • Memory/Available Bytes-大约每个打开的文件减少4k字节(此计数器上的很多抖动:很明显,因为此测试运行了10分钟,所以
  • 内存/池分页字节-大约每个打开的文件3k字节
  • 内存/池非页面字节数-大约每个打开的文件2.2k字节
  • 还有趣的是,进程内存负载并没有以任何显着方式真正增加(如Process/Working Set所跟踪)。

  • 请注意,我还跟踪了分页,并且根本没有使用页面文件(这是我希望的,因为这台机器具有16GB的RAM,最低时我仍有〜4GB的可用空间)。

    关于c++ - 在Windows上打开文件的内存开销是多少?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21309852/

    相关文章:

    winapi - 如何通过 IDispatch 将 SAFEARRAY 传递给 COM 对象?

    c++ - BOOST 库 c++ 的问题

    signals - signal.h中的Siginfo结构已更改-如何容纳?

    c++ - 如何修复无效的 API key 、IP 或操作错误权限?

    windows - 如何找到可移植 git-bash 的驱动器号

    windows - powershell中#的含义

    windows - 为什么 WriteFile 调用 ReadFile 以及如何避免它?

    c++ - 使用 GDI (C++) 绘制带有轮廓的文本

    java - 线程池的设计模式

    windows - SC 创建 binpath 错误