gpt4 book ai didi

c++ - 调用进程退出后是否可以将 DLL 保留在内存中?

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:30:58 24 4
gpt4 key购买 nike

我有一个 DLL 需要 5 到 10 秒才能加载,这意味着我每次编译和运行使用它的可执行文件时都必须等待那么长时间。有没有办法将DLL加载到内存中,以便每次编译相应的可执行文件时都可以立即访问它?如果相关,我正在 QT MinGW 上编译程序。

编辑:到目前为止没有运气。在另一个程序上加载 DLL 似乎没有效果(原始程序仍然加载 DLL,并且需要同样长的时间来加载)。如果 DLL 及其函数已加载到另一个程序中,我想我需要以不同的方式加载它们,但我不知道如何执行此操作。现在我正在使用 LoadLibrary 和 GetProcAddress。

最佳答案

我不是 MinGW 开发人员,但您的问题很常见,并不取决于您如何创建 DLL。这些问题通常可以通过使用三种技术来解决:

  • 选择唯一的 DLL 基地址
  • 绑定(bind) DLL 和 exe(在安装应用程序期间)
  • DLL 延迟加载技术的使用
  • 一点点改善加载时间 DisableThreadLibraryCalls 的调用内部 DLL_PROCESS_ATTACH DllMain 的一部分

  • 您可以使用的链接器或其他工具的确切开关取决于您的开发环境。

    要了解问题,您应该知道如何加载可执行文件或 DLL。首先,EXE 或 DLL 将被映射到内存中。 Memory mapped file (section) 将被创建,它指向 EXE/DLL。因此,您将在访问过程中获得一些地址,这些地址将对应于 EXE/DLL 文件。如果链接 DLL,则可以选择基地址。如果该地址在进程地址空间中未使用,则什么都不做。如果将使用第一行代码(您从 DLL 中调用某个函数),那么将在所用地址附近的 8K 内存页面从文件加载到内存中。如果两个进程使用相同的 DLL,则代码的物理内存将在进程之间共享。即使您持有已初始化的变量,包含变量的页面也将被共享,直到变量的第一次更改。在修改时,将为进行修改的进程制作内存页的拷贝。

    在进程中加载​​ DLL 后,调用者的一些小部分(例如 EXE)必须修改以包含 DLL 中使用的函数的实际地址。对使用另一个 DLL 中的函数的 DLL 也是如此。

    一切听起来都很完美,但是如果您在 DLL 编译期间没有设置任何链接器选项(如果您不使用 --image-base--enable-auto-image-base 链接器选项),您将拥有具有相同基址的所有 DLL(链接器)。所以第一个 DLL 可以在该地址加载。在加载与相同(或某些重叠地址)链接的第二个 DLL 期间,将完成 DLL 的重定位。在重定位过程中,DLL 的代码会被修改,因此 1) DLL 的加载会很慢 2) 代码的修改拷贝将在进程中进行(包括 DLL 使用的内存) 3) 修改拷贝将不会在 DLL 的多个实例之间共享(即使所有实例都将以相同的方式进行修改)。

    我建议你首先使用 Process Explorer例如,验证哪些 DLL 将在您的应用程序中重新定位。您应该在“ View ”/“Lower Pain View”菜单中选择“DLLs”选项,并在“选项”菜单的“配置突出显示”中选中“重定位 DLLs”复选框。您还可以自定义显示每个 DLL 的哪些信息。像下面这样的信息越多,您将看到程序加载越慢,并且在您的应用程序实例之间或使用相同 DLL 的不同应用程序之间不会共享更多地址空间:

    enter image description here

    在上面的示例中,您会看到树 Lenovo DLLs TPOSDSVC.dll , HKVOLKEY.dllTPLHMM.dll链接到相同的基地址 0x10000000并且只有一个 DLL(这里是 TPOSDSVC.dll)会被加载到该地址。另外两个 DLL 必须重新定位。

    我不能在这里写一本关于这个主题的书。我建议您检查您的应用程序关于重定位问题。您可以使用链接器选项( --image-base--enable-auto-image-base 似乎是您需要的)。您可以使用 dumpbin.exe工具(也来自免费版的 Visual Studio)来检查 PE 图像。

    在您的所有 DLL 都有唯一的基地址后,您可以使用另一个工具 bind.exe带选项 -u将 EXE 和您的 DLL 绑定(bind)到其依赖的 DLL。它还将额外减少内存大小并改善应用程序的启动时间。它将更新 IMAGE_DIRECTORY_ENTRY_IMPORTIMAGE_DIRECTORY_ENTRY_DELAY_IMPORT DLL 和 EXE 的一部分(参见 the answer)。 Bind.exe用途 BindImageEx内部 API。许多 Windows 安装程序设置使用 BindImage行动和 BindImage表以在安装 EXE 和 DLL 结束时进行绑定(bind)。

    您可以考虑使用其他技术(请参阅 here )来减小 DLL 和 EXE 的大小。

    我不知道如何在 MinGW 中使用延迟加载技术,但它绝对是可能的。你需要在 Visual Studio 上做两步:include Delayimp.lib作为附加库并使用 /DELAYLOAD选项(请参阅 here )指定应在第一次使用时加载 DLL 中的哪些而不是直接加载。使用非常有用的工具 Dependency Walker您可以看到大多数标准的 Microsoft DLL 都使用该技术。如果您也使用该技术,您可以改善应用程序的启动时间并减少使用的内存。

    关于c++ - 调用进程退出后是否可以将 DLL 保留在内存中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10884331/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com