程序启动过程中加载过多动态库会导致启动变慢,尤其是刚开机时启动程序,加载过多的dll会占用IO,这时候系统IO通常是非常繁忙的,会拖慢启动速度。
动态库加载包括静态加载和动态加载, 静态加载就是使用lib,代码生成过程中链接用的。静态加载可以使用动态库中的导出函数和导出类,但是静态加载是程序启动时加载动态库,会占用启动时间。动态加载用LoadLibrary函数加载动态库,可以随时动态加载DLL,不需要lib,不需要在启动时加载可以节省启动时间。但是只能用GetProcAddress获取导出函数,对导出类通常是无能为力的,相对来说GetProcAddress使用也没有静态加载方便。
动态库延迟加载可以解决上述缺点,既可以不在启动时加载,不占用启动时间,也不需要GetProcAddress获取导出函数,可以直接使用导出函数和导出类(尤其是第三方DLL只提供导出类的情况下)。总体来说即灵活快速,又方便使用。
动态库延迟加载节省了启动时间,也节省了系统资源,刚开机时IO慢时不进行加载,到后面IO不忙的时候加载DLL就会快很多,所以延迟加载并不一定造成后面模块使用时卡顿。
延迟加载设置:
- 在vs项目属性--配置属性--链接器--输入--延迟加载的DLL中设置需要延迟加载的DLL,可以设置多个,用分号隔开。
- 在vs项目属性--配置属性--链接器--输入--附加依赖项 填写DLL对应的lib,或者代码中用#pragma comment( lib,"..\\Lib\\LiveStreamTrans.lib" ) 来加载lib,这里只需要延迟加载的DLL的lib,DLL依赖的但又没有在项目中直接使用的其他DLL的lib不需要。
- 在代码中手动加载DLL,如果有多个DLL,需要包含DLL的依赖DLL,并且要按依赖顺序加载,被依赖的先加载,加载使用LoadLibrary函数,如果不按依赖顺序加载会导致LoadLibrary失败。
- 要注意控制加载时机,DLL函数或者类的使用不能早于该DLL被LoadLibrary,通常如果是懒加载方式,是该功能模块使用时加载,这样比较节省资源;
- 加载相同动态库不要加载多次,外部可以用静态变量判断一下是否加载过。
示例代码如下:
void LiveFuncMgr::LoadAudioDll()
{
LOGI("{}", __FUNCTION__);
static const vector<wstring> delay_load_dlls = {
L"w32-pthreads.dll",
L"postproc-55.dll",
L"swresample-3.dll",
L"swscale-5.dll",
L"avcodec-58.dll",
L"avdevice-58.dll",
L"avfilter-7.dll",
L"avformat-58.dll",
L"avutil-56.dll",
L"libfaac.dll",
L"libfaad2.dll",
L"libglog.dll",
L"libogg.dll",
L"libspeex.dll",
L"libspeexdsp.dll",
L"AudioLive.dll"
//L"LiveStreamTrans.dll"
};
std::wstring wstrDir = util::get_exe_dirw() + L"Plugins\\Live\\deps\\";
for (size_t i = 0; i < delay_load_dlls.size(); ++i)
{
util::load_library((wstrDir + delay_load_dlls[i]).c_str());
}
}
void Init()
{
static bool s_dll_loaded = false;
if (!s_dll_loaded)
{
LiveFuncMgr::GetInstance()->LoadAudioDll();
s_dll_loaded = true;
}
}