在运行时,.NET程序集中的嵌入式资源是从磁盘还是从内存加载的?

在运行时,.NET程序集中的嵌入式资源是从磁盘还是从内存加载的?,.net,.net-assembly,embedded-resource,.net,.net Assembly,Embedded Resource,当我使用GetManifestResourceStream从.NET程序集检索嵌入式资源时,涉及到什么类型的I/O 我认为有两种可能性: 整个程序集在.NET加载时已放入内存,因此GetManifestResourceStream只是在访问内存 当.NET加载程序集时,只有程序集的代码部分被放入内存,因此GetManifestResourceStream需要返回.dll文件以提取嵌入的资源 我很确定第一种情况是这样的,特别是因为可以使用Assembly.Load(Byte[])从原始数据动态加载

当我使用
GetManifestResourceStream
从.NET程序集检索嵌入式资源时,涉及到什么类型的I/O

我认为有两种可能性:

  • 整个程序集在.NET加载时已放入内存,因此
    GetManifestResourceStream
    只是在访问内存

  • 当.NET加载程序集时,只有程序集的代码部分被放入内存,因此
    GetManifestResourceStream
    需要返回
    .dll
    文件以提取嵌入的资源

  • 我很确定第一种情况是这样的,特别是因为可以使用
    Assembly.Load(Byte[])
    从原始数据动态加载程序集。但是我想知道如果嵌入了一个非常大的文件(比如说几GB),会发生什么情况——第二种选择可能更有效。大小重要吗

    只是挑战了一些长期以来的假设,在这方面找不到太多的参考资料。

    对于Windows、Linux、MacOS等按需分页的虚拟内存操作系统,“内存”不是一个足够精确的术语。CLR使用内存映射文件(MMF)将程序集映射到进程的地址空间。只需向处理器发送数字,每4096字节一个。还没有从文件中读取任何内容

    这会被延迟,直到程序尝试从地址空间内的地址读取。第一次访问产生一个页面错误,内核为页面分配RAM,并用文件内容填充页面。之后,程序恢复,好像什么都没发生。强大地增强了虚拟内存的“你不用为你不用的东西付费”优势

    这里没有“提取”,您直接从内存读取资源数据,这是实现它的最有效方法。嵌入式资源的行为与文件中的其他数据(如元数据和MSIL)没有任何不同。同样,您也不会为程序集中从未调用过的任何代码付费

    请记住,嵌入式资源占用与GC堆相同的OS资源,它也需要地址空间。唯一真正的区别是GC堆地址空间由OS分页文件支持,并且永远不能与其他进程共享,程序集数据由程序集文件支持,并且可以共享。大型资源显著地减少了您在.NET程序中可以分配的内存量,即使您从未使用过它们。这只在32位进程中重要,64位进程有很多TB的地址空间


    另一个限制是,MMF视图永远不能大于2GB,即使在64位进程中也是如此,这为资源的最大大小设置了硬上限。这通常很早就结束了,使用CS1566构建失败,“指定的参数超出了有效值的范围”。顺便说一句,这不是一个很好的诊断工具。

    我不知道,但是千兆字节。。。?你确定没有比作为嵌入式资源更好的存储和分发内容的方法了吗?当然,这只是一个假设。我认为必须对允许的最大资源大小进行限制,或者对如何加载如此大的资源进行分支。我对.NET一无所知,但通常现代操作系统允许您虚拟地将文件映射到内存中,然后在访问该内存地址时提取文件的特定部分。因此,它只加载被访问的数据块,而实际上假装它已在内存中完全加载,占用了“千兆字节”的虚拟地址空间(在32b平台上可能会有问题!…在64b上可能没什么大不了的)。说清楚的是,我通常有几kb或1MB左右的嵌入式资源。我只是好奇I/o性能,以及大文件是否发生了不同的情况。@MattJohnson Pint根据公认的答案,我很确定第一种情况是错误的?那么在程序运行期间,嵌入式资源将始终处于堆中?我本以为它被编译成了可执行文件,然后每当需要资源时,它就会从磁盘中引用内存并将其复制出来,虽然我想这不会比从磁盘读取文件更有效……但我想我一直认为资源是用来避免引用和管理经常被引用的文件(例如徽标),而不是作为性能提升工具。不,堆与此无关。它只占用地址空间。MMF的优点是,您不必显式地从文件中读取它,不需要分页文件中的空间,可以自动缓存,因此任何后续访问都非常便宜,并且可以在其他进程需要RAM时简单地丢弃。按需分页虚拟内存操作系统的优点在于,它使用了所有这些优点。