【问题标题】:Discarding DLL's resource after using it使用后丢弃 DLL 的资源
【发布时间】:2014-06-12 08:15:04
【问题描述】:

我正在创建一个带有嵌入式二进制资源的 dll。目前,当我加载这个 DLL 时,它会将内存映射到我的进程地址空间中。问题是嵌入的二进制资源非常庞大,我不想在使用完后保留它。

我尝试查找有关此的文档,显然 PE 文件中的某些部分没有获得内存映射(重定位部分)。此外,我可以创建新部分并将其标记为 IMAGE_SCN_MEM_DISCARDABLE,但此标记在内核模式之外被忽略。

有一个 win API 函数支持为 16 位 Windows 释放资源,但不适用于 32 位以上。 documentation 表示“此功能已过时,仅支持向后兼容 16 位 Windows。对于 32 位 Windows 应用程序,无需释放使用 LoadResource 加载的资源。如果在 32 位或 64 位上使用Windows 系统,此函数将返回 FALSE”。我不知道他们的意思是什么,但似乎他们并不期望资源很大并且可以容纳在地址空间中。

在我使用完加载的资源后,我有什么办法可以继续丢弃它们?

【问题讨论】:

  • 可执行文件的 .rsrc 部分已经可以丢弃。除非您出于某种原因需要地址空间,否则帮助没有任何意义。 64 位操作系统本身就是一个迅速消失的问题,正在变得普遍。您可以将资源放在另一个 DLL 中,以便显式卸载它。

标签: c++ windows winapi dll portable-executable


【解决方案1】:

如果需要,系统会丢弃它们。只要您不引用内存,如果系统需要物理内存来做其他事情,它就可以被丢弃和分页。因此,它不会停止将物理内存用于需要它的地方。

也就是说,链接资源并不打算很大。关键是一个模块被映射到一个连续的内存范围。如果您的模块真的很大,那么可能无法找到如此连续的内存范围。更重要的是,模块的地址范围是为资源的整个生命周期保留的。这意味着进程中没有其他任何东西可以使用该虚拟内存地址范围。因此,即使可以找到一个连续的地址范围,它也会永远为模块保留,并且该地址范围不能用于其他任何事情。这很容易成为 32 位应用程序的问题。

因此,将大量资源放在内存中不会导致物理资源的长期消耗,但会不可避免地限制虚拟内存地址空间资源。

得出的结论是,如此巨大的对象应该保存在外部文件中,而不是作为资源链接到模块。如果您绝对必须使用 PE 模块中的资源,则将该资源放入单独的 DLL 中。使用LoadLibrary 加载DLL,使用从LoadLibrary 获得的模块句柄提取资源,然后使用FreeLibrary 卸载DLL。

【讨论】:

  • 谢谢大卫!我同意将它们作为外部文件是最好的解决方案,但是,我们的应用程序可以构建 DLL,我们压缩并添加多个二进制文件作为资源,有时文件数量会增长到很大。我们的客户使用 DLL,他们倾向于将其复制到不同的位置,并且不希望他们必须复制另一个文件。我们正在寻找的解决方案是必须围绕单个文件进行复制,但在加载时能够将其视为单个文件。有没有办法我们可以将一个大文件添加到 DLL 中,并且在 DLL 加载时不对其进行内存映射?
  • 不,没有这种方法可以部分取消映射 DLL。唯一的方法是使用外部文件或单独的 DLL,然后可以通过调用 FreeLibrary 来卸载。
  • 也许他可以启动一个子进程,其唯一的工作就是加载 DLL(因此可以简单到保留连续内存不应该成为问题),然后只复制他实际需要的数据跨越流程边界?
猜你喜欢
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
  • 2016-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多