当我使用 GetManifestResourceStream
要从 .NET 程序集中检索嵌入式资源,涉及哪种 I/O?
我看到两种可能性:
GetManifestResourceStream
只是访问内存。 GetManifestResourceStream
需要回到.dll
文件以提取嵌入的资源。 我很确定第一个是这种情况,特别是因为可以使用
Assembly.Load(Byte[])
从原始数据动态加载程序集。 .但是后来我想知道如果嵌入了一个非常大的文件(比如几个千兆字节)会发生什么 - 第二种选择可能更有效。大小重要吗?只是挑战一些长期持有的假设,并不能在这方面找到太多的引用方式。
最佳答案
对于 Windows、Linux、MacOS 等按需分页的虚拟内存操作系统,“内存”这个词不够准确。 CLR 使用内存映射文件 (MMF) 将程序集映射到进程的地址空间。只是给处理器编号,每 4096 个字节一个。尚未从文件中读取任何内容。
这会延迟到程序尝试从地址空间内的地址读取。第一次访问会产生页面错误,内核为页面分配 RAM 并用文件内容填充它。之后程序继续,好像什么也没发生。有力地赋予了虚拟内存的“你不为你不使用的东西付费”的优势。
没有“提取”,您是直接从内存中读取资源数据,这是实现它的最有效方式。嵌入资源的行为与文件中的其他数据(如元数据和 MSIL)没有任何不同。同样,您也无需为您从未调用过的程序集中的任何代码付费。
请记住,嵌入式资源占用与 GC 堆相同的操作系统资源,它也需要地址空间。唯一真正的区别是 GC 堆地址空间由 OS 分页文件支持,永远不能与其他进程共享,程序集数据由程序集文件支持并且可以共享。大型资源显着减少了您可以在 .NET 程序中分配的内存量,即使您从不使用它们。这仅在 32 位进程中很重要,64 位进程具有许多 TB 的地址空间。
另一个限制是,即使在 64 位进程中,MMF View 也不能大于 2 GB,这对资源的最大大小设置了硬上限。这通常很早就结束了,使用 CS1566 构建失败,“指定的参数超出了有效值的范围”。顺便说一句,这不是一个很好的诊断。
关于.net - .NET 程序集中的嵌入式资源是在运行时从磁盘加载还是从内存加载?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43548270/