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

时间:2017-04-21 16:59:41

标签: .net .net-assembly embedded-resource

当我使用GetManifestResourceStream从.NET程序集中检索嵌入式资源时,涉及哪种I / O?

我看到两种可能性:

  1. 当.NET加载它时,整个程序集已经被放入内存中,因此GetManifestResourceStream只是访问内存。

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

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

    只是挑战一些长期存在的假设,并且无法在此基础上找到太多参考。

1 个答案:

答案 0 :(得分:15)

"存储"在Windows,Linux,MacOS等需求页面虚拟内存操作系统上,这个术语不够准确。 CLR使用内存映射文件将程序集映射到进程的地址空间。只是处理器的数字,每4096字节一个。暂时没有从文件中读取任何内容。

直到程序尝试从地址空间内的地址读取时才会延迟。第一次访问会生成页面错误,内核会为页面分配RAM并使用文件内容填充它。之后程序恢复,好像什么也没发生。强烈支持你不会为你不能使用的东西买单#34;虚拟内存的优势。

没有"提取",您正在直接从内存中读取资源数据,这是最有效的方式。嵌入式资源的行为与文件中的其他数据不同,例如元数据和MSIL。您同样不会为您从未打过电话的程序集中的任何代码付费。

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

另一个限制是MMF视图永远不会大于2 GB,即使在64位进程中,也会设置资源最大大小的硬上限。这通常很早就开始了,没有使用CS1566进行构建,"指定的参数超出了有效值的范围"。不是一个很好的诊断btw。