代码之家  ›  专栏  ›  技术社区  ›  mj2008

如果加载的dll被卸载,是否会删除该dll?

  •  8
  • mj2008  · 技术社区  · 16 年前

    使用标准的Windows应用程序。它使用loadlibrary加载一个dll来调用其中的函数(我们将调用这个dll_a)。该函数加载另一个dll(我们称之为dll_b)。应用程序现在使用Freelibrary卸载一个dll,因为它不再需要它。

    问题是: dll_b是否仍在内存中并已加载?

    这是我可以依赖的东西,还是没有文件证明?

    4 回复  |  直到 16 年前
        1
  •  11
  •   Michael Burr    16 年前

    不。 DLL_B 不会卸载。这个 LoadLibrary() 呼叫由 DLL_A 将增加的负载计数 DLLYB . 因为没有对应的 FreeLibrary() 需要 DLLYB ,refcount不会变为零。

    从loadLibrary()文档:

    系统维护每个进程 所有加载模块的引用计数。 调用LoadLibrary会增加 引用计数。调用 FreeLibrary或 Freelibraryandextitthread函数 减少引用计数。这个 系统卸载模块时 参考计数为零或何时 进程终止(无论 参考计数)。

        2
  •  3
  •   Brian R. Bondy    16 年前

    在这种情况下,您会有一个手柄泄漏:

    Program -Load> Dll A 
              -Load> Dll B 
            -Unload> Dll A
    

    正在卸载的模块不会隐式执行任何代码,以卸载它加载的模块。

    由于没有执行任何代码来减少引用计数,因此模块B将永远不会被卸载。

    以下是加载/卸载DLL的规则:

    • 每次调用LoadLibrary和LoadLibraryEx都会增加该模块的引用计数。这只存在于调用进程的上下文中,而不是跨进程边界。
    • 每次调用freelibrary或freelibraryandexthread都会减少引用计数。
    • 当引用计数达到0时,将卸载它。
    • 当Windows看到您的程序 关闭 ,然后卸载任何泄漏的卸载模块。
    • 取决于你在做什么, DllCanUnloadNow 可能对你有用。

    仍在内存中vs仍在加载:

    当引用达到0时,不能保证您的模块在某个时间从内存中释放。但您应该将模块视为在引用计数达到0时卸载。

    正在停止卸载dll:

    要强制卸载dll,可以尝试

    • 系统使用dll_process_detach标志调用dllmain。您可以尝试通过某种阻塞操作从中返回。
    • 您可以尝试从您希望无法卸载的dll中调用LoadLibrary。(自负载)

    编辑:

    您提到过您的目标是将代码喷射到正在运行的程序中,并且您希望故意泄漏句柄。

    这很好,但是如果您经常运行这个操作,可能会导致源程序崩溃,因为会使用太多的句柄,或者最终会使用太多的内存。

    您可以从dllmain返回false以阻止加载它,这样就不会浪费内存。当fdwareson为dll_process_attach时,可以执行此操作。你可以 read more about it here .

    如果您试图模拟一个dll并添加您自己的额外功能,您将需要实现源dll实现的所有功能,并将每个调用委托回源dll。

        3
  •  1
  •   dirkgently    16 年前

    阅读 评论 详细解释。

    需要注意的关键是:

    系统为每个加载的模块维护每个进程的引用计数。

    再往下走

    当模块的引用计数为零或进程终止时,系统将从进程的地址空间中卸载模块。

    MSDN :

    释放加载的动态链接库(DLL)模块,并在必要时减少其引用计数。当引用计数为零时,模块将从调用进程的地址空间中卸载,并且句柄不再有效。

        4
  •  1
  •   grieve    16 年前

    Windows中的DLL被引用计数。卸载A时,您正在减少A上的引用计数,如果它达到零,则将卸载它,并且(假定代码中没有错误)将减少B上的引用计数。如果B上的引用计数变为零,则将卸载它。DLL C可能在B上有refcount,卸载A将不会卸载B。