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

标签 .net .net-assembly embedded-resource

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

我看到两种可能性:

  • 当 .NET 加载整个程序集时,它已经被放入内存,所以 GetManifestResourceStream只是访问内存。
  • .NET 加载程序集时,只有程序集的代码部分被放入内存,所以 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/

    相关文章:

    plugins - .NET 反射器 + Reflexil 插件

    embedded-resource - 如何发布游戏?

    java - java中访问jar位于资源的多平台方式

    java - 从资源中的图像设置图标图像

    c# - 添加到 Observable 集合时的奇怪行为

    .net - 哪些文件应该进行数字签名

    c# - .NET async\await 基础知识

    c# - 即使版本号错误,依赖程序集解析也会成功

    .net - 通过 Web 服务将 Sql Server 转换为 Excel

    c# - 如何在运行时 C# 中搜索嵌入式文件