简述
在现代Windows系统中,打开一个文件需要多少内存?一些应用程序需要打开“大量”文件。Windows很擅长打开“大量”文件,但是保持单个文件的打开负载如何,以便可以决定何时“太多”是“太多”?
背景
对于在32位进程内顺序处理较大数据集(100MB〜几GB)的情况,我们需要设计一个缓冲区,将其内容存储在磁盘而不是内存中。
我们使用CreateFile
与FILE_ATTRIBUTE_TEMPORARY
和FILE_FLAG_DELETE_ON_CLOSE
创建了一个小型类,没有太多问题。
问题在于,这些缓冲区的使用方式是每个缓冲区(每个临时文件)可能存储从几个字节到几GB的数据,并且我们希望使缓冲区类本身尽可能简化和通用。
使用情况范围从每个具有约100MB的100个缓冲区到每个仅具有几个字节的数千个缓冲区。 (是的,每个缓冲区在这个意义上都有自己的文件。)
在缓冲类中包含一个缓冲阈值似乎是很自然的,只有当它实际存储的字节数超过创建+引用临时文件的(内存)开销时,才开始创建和使用磁盘上的临时文件 - 在进程中以及在物理机器内存负载上。
问题
在现代Windows系统中,打开一个(临时)文件占用多少字节的内存?
- 使用
CreateFile
与FILE_ATTRIBUTE_TEMPORARY
和FILE_FLAG_DELETE_ON_CLOSE
- 打开文件的(32位)进程的虚拟地址空间的字节数
- 机器上的物理内存字节数(包括任何内核数据结构)
也就是说,当你开始从将数据存储在内存中转而存储在文件中时,净主内存增益的阈值是多少字节(在进程内部以及物理上)?
注释:
该评论提到 打开文件限制 不适用于CreateFile
,只适用于 MS CRT 文件 API。(通过 CreateFile 打开 10.00s 的文件在我的系统上完全没有问题——这是否是一个好主意是完全不同的问题,并且 不是本问题的一部分。
内存映射文件:完全不适合处理 32 位进程中的 GB 级数据,因为您不能可靠地将这么大的数据集映射到 32 位进程的正常 2GB 地址范围内。 对于我的问题来说是完全没用的,与实际问题毫无关系。对于后台问题,普通文件就可以了。
看了一下http://blogs.technet.com/b/markrussinovich/archive/2009/09/29/3283844.aspx - 告诉我在64位系统上HANDLE
本身占用16个字节,但那只是句柄。
看了一下STXXL和它的文档,但这个库不适合我的任务,也没有找到在开始实际使用文件之前有用的阈值的提及。
有用的评论摘要:
Raymond 写道:“答案会因所安装的杀毒软件而异,所以唯一的方法就是在生产配置上进行测试。”
qwm 写道:“我更关心CPU开销。无论如何,回答你的问题最好的方法是测试。我能说的是,_FILE_OBJECT
的大小(包括 _OBJECT_HEADER
)约为300字节,它的一些字段是指向其他相关结构的指针。”
Damon writes:“一个正确的答案是:10个字节(在我的Windows 7机器上)。由于似乎没有人觉得值得尝试,所以我尝试了一下(测量了100k次调用中MEMORYSTATUSEX::ullAvailVirtual
的差异,没有其他运行程序)。别问我为什么不是8或16个字节,我也不知道。大约需要17秒的内核时间,退出时进程有100,030个句柄打开。私有工作集在运行期间增加了412k,而全局可用VM减少了1M,因此大约60%的内存开销在内核内部。(...)”
CreateFile
显然消耗了大量的内核时间(即繁忙的 CPU 时间,而不是像等待磁盘那样的时间!)。100k 次调用需要 17 秒,相当于在该计算机上打开一个句柄需要约 450,000 个周期。与此相比,虚拟内存只减少了 10 字节,可以说是微不足道的。
_FILE_OBJECT
本身(包括_OBJECT_HEADER
)的大小约为300字节,并且它的一些字段是指向其他相关结构体的指针。 - qwm