-
显式加载 (Explicit Loading)
显式加载动态库是通过在运行时使用特定的函数来加载动态库,通常需要提供库的路径和库的符号名称。这种方法需要程序员在代码中明确调用库加载和符号解析函数。
- Windows:使用
LoadLibrary加载动态库,使用GetProcAddress获取库中函数的地址。 - Linux/Unix:使用
dlopen加载动态库,使用dlsym获取库中函数的地址。 - 这种方式通常用于插件系统、动态加载模块等场景。
- Windows:使用
-
隐式加载 (Implicit Loading)
隐式加载是指在程序启动时,操作系统会根据可执行文件的要求自动加载所依赖的动态库。程序员不需要显式地调用加载函数,只需要在程序的构建过程中指定库的依赖。
- Windows:通过
dllimport声明来隐式加载动态库,操作系统会在启动时根据需要加载动态库。 - Linux/Unix:通过
ld(链接器) 指定库依赖,操作系统会在运行时自动加载。
- Windows:通过
隐式加载通常发生在程序启动时,操作系统自动加载依赖的动态库。这种方式适用于以下场景:
- 场景:如果你的程序依赖的库在运行时是固定的,并且不需要频繁更换或更新,那么隐式加载是一个理想选择。
- 例子:常见的桌面应用程序、大多数命令行工具,它们在构建时就链接了所依赖的动态库。
-
场景:当程序启动时,你不希望自己显式地管理每个库的加载,而是希望操作系统根据程序的可执行文件和库的依赖自动加载它们。
-
例子:操作系统自动加载依赖的系统库(如
libc、kernel32.dll等)以及应用程序中显式链接的第三方库。
- 场景:如果你的程序没有插件机制,且库和可执行文件之间的关系非常紧密,隐式加载更简洁,开发人员不需要显式地控制加载逻辑。
- 例子:一个使用 CMake 管理的普通项目,链接了一些共享库,程序启动时,操作系统会自动加载这些库。
- 场景:对于在系统中全局共享的动态库,隐式加载可以通过操作系统的库版本管理来确保正确的库被加载(比如
libssl的不同版本)。 - 例子:在 Linux 系统中,当你通过
find_library或target_link_libraries链接一个库时,操作系统会自动加载相应的版本。
显式加载需要程序在运行时明确调用特定的函数来加载库,并在需要时手动管理符号解析。适用于以下场景:
- 场景:如果你的应用程序需要支持插件或模块化架构(即在运行时动态加载外部模块或插件),显式加载是必须的。
- 例子:IDE、图像处理工具或其他应用程序,它们支持加载不同的插件或扩展功能,而这些插件在程序启动时并不一定存在。
- 方法:通过
dlopen或LoadLibrary动态加载插件库,并使用dlsym或GetProcAddress获取函数指针。
- 场景:当你的程序需要根据运行时的某些条件来选择加载特定的库时,显式加载是最佳选择。
- 例子:应用程序根据系统架构、操作系统类型或用户输入,动态加载不同的库。
- 方法:在 C++ 中,使用
dlopen和dlsym动态选择和加载特定库,或者使用LoadLibrary和GetProcAddress在 Windows 上执行类似操作。
- 场景:如果你需要支持热更新(如替换已加载的动态库),显式加载方式更为灵活,因为你可以在运行时控制库的卸载和重新加载。
- 例子:游戏引擎可能需要在运行时加载或替换资源管理库、图形渲染库等。
- 方法:通过显式的库加载机制,应用程序能够在运行时加载和卸载库,而不是依赖操作系统的自动加载。
- 场景:当你需要处理多个版本的库,或者库的不同部分在不同的时间被加载时,显式加载允许你对库的加载时机和顺序进行精确控制。
- 例子:某些软件可能需要同时加载多个不同版本的相同库,或者通过不同的符号重定向来解决依赖冲突。
- 场景:显式加载允许你在程序的生命周期内只在需要时加载库,从而避免不必要的内存消耗或提高程序启动速度。
- 例子:游戏引擎根据用户的操作需求来加载相应的模块或资源库,不会在游戏启动时加载所有库,而是按需加载。
- 隐式加载适用于:依赖固定且少变、无需动态选择库的场景,简化了开发和维护工作。
- 显式加载适用于:需要动态加载库、插件或模块化设计、按需选择库、热更新等场景,提供更大的灵活性和控制力。