.NET 程序集中的嵌入式资源是在运行时从磁盘还是从内存加载? [英] Are embedded resources in a .NET Assembly loaded from disk or from memory at runtime?

查看:30
本文介绍了.NET 程序集中的嵌入式资源是在运行时从磁盘还是从内存加载?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我使用 GetManifestResourceStream 从 .NET 程序集中检索嵌入资源时,涉及什么样的 I/O?

When I use GetManifestResourceStream to retrieve an embedded resource from a .NET assembly, what kind of I/O is involved?

我看到两种可能性:

  1. 整个程序集在 .NET 加载时已经放入内存中,所以 GetManifestResourceStream 只是访问内存.

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

Only the code parts of the assembly were put into memory when the assembly was loaded by .NET, so GetManifestResourceStream needs to go back to the .dll file to extract the embedded resource.

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

I'm pretty sure the first is the case, especially since assemblies can be loaded dynamically from raw data with Assembly.Load(Byte[]). But then I wonder what happens if a very large file (say several gigabytes) was embedded - the second option might be more efficient. Does size matter?

只是挑战一些长期存在的假设,在这方面找不到太多参考.

Just challenging some long-held assumptions, and not able to find much in the way of reference on this.

推荐答案

在 Windows、Linux、MacOS 等按需分页虚拟内存操作系统上,内存"并不是一个足够精确的术语.CLR 使用内存映射文件 (MMF) 将程序集映射到进程的地址空间.只是给处理器编号,每 4096 个字节一个.尚未从文件中读取任何内容.

"Memory" is not a precise enough term on a demand-paged virtual memory operating system like Windows, Linux, MacOS. The CLR maps the assembly into the address space of the process using a memory-mapped file (MMF). Just numbers to the processor, one each for every 4096 bytes. Nothing is read from the file just yet.

这会被延迟,直到程序尝试从地址空间内的地址读取.第一次访问会产生一个页面错误,内核为页面分配 RAM 并用文件内容填充它.之后程序恢复,好像什么也没发生.强力赋能虚拟内存的不用付钱"的优势.

That is delayed until the program tries to read from an address inside the address space. First access generates a page fault, the kernel allocates RAM for the page and fills it with the file content. After which the program resumes as though nothing happened. Strongly empowers the "you don't pay for what you don't use" advantage of virtual memory.

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

There is no "extraction", you are reading the resource data directly from memory, most efficient way it could have been implemented. An embedded resource does not otherwise behave any differently from other data in the file, like the metadata and the MSIL. You likewise don't pay for any code in the assembly that you never call.

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

Do keep in mind that an embedded resource occupies the same OS resource as the GC heap, it too requires address space. Only real difference is that GC heap address space is backed by the OS paging file and can never be shared with other processes, the assembly data is backed by the assembly file and can be shared. Large resources notably shrink the amount of memory you can allocate in a .NET program, even if you never use them. That matters only in a 32-bit process, a 64-bit process has many terabytes of address space.

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

Another restriction is that an MMF view can never be larger than 2 GB, even in a 64-bit process, that sets a hard upper limit on the maximum size of a resource. That usually keels over very early, failing the build with CS1566, "Specified argument was out of the range of valid values". Not a great diagnostic btw.

这篇关于.NET 程序集中的嵌入式资源是在运行时从磁盘还是从内存加载?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆