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

时间:2014-01-23 13:41:25

标签: c++ windows winapi file-io createfile

TL; DR

在现代Windows系统上打开文件需要多少内存?某些应用程序加载需要打开“大量”文件。 Windows能够打开“大量”文件,但是保持单个文件打开的负担是什么,以便人们可以决定“很多”是“太多”?

背景

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

我们在没有太多问题的情况下充实了一个小课程(使用CreateFile FILE_ATTRIBUTE_TEMPORARYFILE_FLAG_DELETE_ON_CLOSE)。

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

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

在缓冲区类中包含一个缓冲区阈值似乎很自然,当缓冲区类实际存储的字节多于创建+引用临时文件时使用的(内存)开销时,它只开始创建和使用临时磁盘文件 - 在进程中以及在物理机器内存上加载。

问题

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

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

也就是说,当您开始在文件中而不是在内存中存储数据时,看到净主内存增益(进程内和物理上)的阈值(以字节为单位)是什么?

说明:

提及的评论open file limit不适用于CreateFile,仅适用于MS CRT文件API。 (通过CreateFile打开10.00s文件在我的系统上完全没问题 - 这是一个好主意是不是完全不同而且不是这个问题的一部分

内存映射文件:完全不适合在32位进程中处理GB数据,因为您无法将这些大型数据集可靠地映射到32位进程的正常2GB地址范围。 < em>完全对我的问题毫无用处,并且完全不以任何方式与实际问题相关。普通文件适合背景问题。

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

查看了STXXL和它的文档,但是这个lib也不适用于我的任务,在开始实际使用文件之前,我没有发现任何有用的阈值。


有用的评论摘要:

Raymond writes:“答案会因安装的防病毒软件而异,因此唯一可以知道的是在生产配置上对其进行测试。”

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

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

“更令人震惊的是,CreateFile明显消耗了大量的内核时间(繁忙的CPU时间,而不是在磁盘上等待!)。对于100k呼叫,17秒就可以归结为大约450,000个周期在这台机器上打开一个手柄。相比之下,仅仅10个字节的虚拟内存就可以忽略不计了。“

1 个答案:

答案 0 :(得分:5)

我现在做了一些测量:

  • 我设置了一个带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免费)。