Skip to content

Latest commit

 

History

History
82 lines (49 loc) · 5.31 KB

File metadata and controls

82 lines (49 loc) · 5.31 KB

动态库加载方式介绍

动态库的加载方式主要有以下两种

  1. 显式加载 (Explicit Loading)

    显式加载动态库是通过在运行时使用特定的函数来加载动态库,通常需要提供库的路径和库的符号名称。这种方法需要程序员在代码中明确调用库加载和符号解析函数。

    • Windows:使用 LoadLibrary 加载动态库,使用 GetProcAddress 获取库中函数的地址。
    • Linux/Unix:使用 dlopen 加载动态库,使用 dlsym 获取库中函数的地址。
    • 这种方式通常用于插件系统、动态加载模块等场景。
  2. 隐式加载 (Implicit Loading)

    隐式加载是指在程序启动时,操作系统会根据可执行文件的要求自动加载所依赖的动态库。程序员不需要显式地调用加载函数,只需要在程序的构建过程中指定库的依赖。

    • Windows:通过 dllimport 声明来隐式加载动态库,操作系统会在启动时根据需要加载动态库。
    • Linux/Unix:通过 ld (链接器) 指定库依赖,操作系统会在运行时自动加载。

显式加载和隐式加载使用场景

隐式加载 (Implicit Loading)

隐式加载通常发生在程序启动时,操作系统自动加载依赖的动态库。这种方式适用于以下场景:

1. 依赖库固定且不频繁变化
  • 场景:如果你的程序依赖的库在运行时是固定的,并且不需要频繁更换或更新,那么隐式加载是一个理想选择。
  • 例子:常见的桌面应用程序、大多数命令行工具,它们在构建时就链接了所依赖的动态库。
2. 程序启动时加载
  • 场景:当程序启动时,你不希望自己显式地管理每个库的加载,而是希望操作系统根据程序的可执行文件和库的依赖自动加载它们。

  • 例子:操作系统自动加载依赖的系统库(如 libckernel32.dll 等)以及应用程序中显式链接的第三方库。

3. 简单的应用程序或服务
  • 场景:如果你的程序没有插件机制,且库和可执行文件之间的关系非常紧密,隐式加载更简洁,开发人员不需要显式地控制加载逻辑。
  • 例子:一个使用 CMake 管理的普通项目,链接了一些共享库,程序启动时,操作系统会自动加载这些库。
4. 共享库的版本管理
  • 场景:对于在系统中全局共享的动态库,隐式加载可以通过操作系统的库版本管理来确保正确的库被加载(比如 libssl 的不同版本)。
  • 例子:在 Linux 系统中,当你通过 find_librarytarget_link_libraries 链接一个库时,操作系统会自动加载相应的版本。

显式加载 (Explicit Loading)

显式加载需要程序在运行时明确调用特定的函数来加载库,并在需要时手动管理符号解析。适用于以下场景:

1. 插件或模块化架构
  • 场景:如果你的应用程序需要支持插件或模块化架构(即在运行时动态加载外部模块或插件),显式加载是必须的。
  • 例子:IDE、图像处理工具或其他应用程序,它们支持加载不同的插件或扩展功能,而这些插件在程序启动时并不一定存在。
  • 方法:通过 dlopenLoadLibrary 动态加载插件库,并使用 dlsymGetProcAddress 获取函数指针。
2. 运行时选择库
  • 场景:当你的程序需要根据运行时的某些条件来选择加载特定的库时,显式加载是最佳选择。
  • 例子:应用程序根据系统架构、操作系统类型或用户输入,动态加载不同的库。
  • 方法:在 C++ 中,使用 dlopendlsym 动态选择和加载特定库,或者使用 LoadLibraryGetProcAddress 在 Windows 上执行类似操作。
3. 热更新或库替换
  • 场景:如果你需要支持热更新(如替换已加载的动态库),显式加载方式更为灵活,因为你可以在运行时控制库的卸载和重新加载。
  • 例子:游戏引擎可能需要在运行时加载或替换资源管理库、图形渲染库等。
  • 方法:通过显式的库加载机制,应用程序能够在运行时加载和卸载库,而不是依赖操作系统的自动加载。
4. 版本兼容或依赖管理
  • 场景:当你需要处理多个版本的库,或者库的不同部分在不同的时间被加载时,显式加载允许你对库的加载时机和顺序进行精确控制。
  • 例子:某些软件可能需要同时加载多个不同版本的相同库,或者通过不同的符号重定向来解决依赖冲突。
5. 内存或性能优化
  • 场景:显式加载允许你在程序的生命周期内只在需要时加载库,从而避免不必要的内存消耗或提高程序启动速度。
  • 例子:游戏引擎根据用户的操作需求来加载相应的模块或资源库,不会在游戏启动时加载所有库,而是按需加载。

总结

  • 隐式加载适用于:依赖固定且少变、无需动态选择库的场景,简化了开发和维护工作。
  • 显式加载适用于:需要动态加载库、插件或模块化设计、按需选择库、热更新等场景,提供更大的灵活性和控制力。