【问题标题】:What is the memory overhead of opening a file on Windows?在 Windows 上打开文件的内存开销是多少?
【发布时间】:2014-02-14 02:24:13
【问题描述】:

TL;DR

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

背景

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

我们已经充实了一个没有太多问题的小类(使用CreateFileFILE_ATTRIBUTE_TEMPORARYFILE_FLAG_DELETE_ON_CLOSE)。

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

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

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

问题

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

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

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

注意事项:

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

内存映射文件:完全不适合在 32 位进程中处理 GB 的数据,因为您无法可靠地将如此大的数据集映射到 32 位进程的正常 2GB 地址范围。 是 完全对我的问题毫无用处,并且在任何情况下都与实际问题无关。普通文件对于后台问题来说就很好了。

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

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


有用的cmets总结:

Raymondwrites:“答案会因安装的防病毒软件而异,因此唯一知道的方法是在生产配置上进行测试。”

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

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

“更令人惊叹的是CreateFile 显然消耗了大量的内核时间(这是繁忙的 CPU 时间,而不是像在磁盘上等待的时间!)。100k 调用的 17 秒归结为打开一个调用大约 450,000 个周期在这台机器上处理。相比之下,仅仅 10 字节的虚拟内存消失是微不足道的。”

【问题讨论】:

  • 您要处理的数据是否分散在大数据集周围?另外,您是否查看过 Boost 对内存映射文件的支持?
  • 100.000s of buffers with just a few bytes each你做错了。
  • “将其内容存储在磁盘上的缓冲区”对我来说听起来像是内存映射文件。 MapViewOfFile 文件。除非我误解,否则数十万个缓冲区对我来说听起来很疯狂。
  • @MartinBa 我会更关心 CPU 开销。无论如何,回答您的问题的最佳方法是对其进行测试。我只能说_FILE_OBJECT(包括_OBJECT_HEADER)的大小约为300b,其中一些字段是指向其他相关结构的指针。
  • (不管这是否是一个好主意)我知道有人可能对此有更详细的信息,这就是你问的原因,但如果你真的担心开销,如果这是偶数可能的话你可以试试看:P。打开 100k 个文件(当然是在循环中),然后向它们写入和读取一些内容,以确保操作系统确实打开了它们,然后看看会发生什么。

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


【解决方案1】:

我现在做了一些测量:

  • 我设置了一个 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 的空闲空间)。

【讨论】:

  • 您是否对创建和打开文件句柄通常需要多长时间进行了基准测试?
猜你喜欢
  • 1970-01-01
  • 2013-05-20
  • 1970-01-01
  • 1970-01-01
  • 2017-02-20
  • 1970-01-01
  • 2010-09-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多