Qt动态加载和卸载QWebEngine模块

Qt动态加载和卸载QWebEngine模块。最终是失败的,记录尝试的几种方法。

exe编译链接了QtWebEngine模块之后,程序启动则加载了Qt6WebEngineWidgets和Qt6WebEngineCore,内存占用多了40MB以上,线程占用十多个。而一旦创建QWebEngineProfile,则内存占用更多,同时启动了QtWebEngineProcess.exe。而本人的程序中,大部分时候不需要QWebEngineView,需要使用的时候,又多以子控件形式存在,不便剥离为独立的exe子程序。因此,想动态加载和卸载QtWebEngine。

方法一:QWebEngineProfile::defaultProfile()。在新版本的Qt6中,defaultProfile已经改为无痕隐身模式,这个和此前相反。而默认的QWebEngineView则会使用它。所以,一般情况下,我们必须new一个自己的QWebEngineProfile,也就用不到QWebEngineProfile::defaultProfile()。因此,尝试:delete QWebEngineProfile::defaultProfile() 。结果,意料之外的事情发生了,Qt6WebEngineWidgets.dll和Qt6WebEngineCore.dll居然全部从进程中卸载了!就在我以为达到自己预期时,程序很快崩溃。当然,即使不崩溃,也已经无法在重新调用QtWebEngine模块的任何功能了。

方法二:既然无法卸载dll,那么,如果自己new的QWebEngineProfile,在空闲时直接delete回收,也不错!我尝试了几个方法,由于代码糅合较多,只简单改改,但存在一些崩溃的情况。为什么要回收QWebEngineProfile呢?因为回收后,QtWebEngineProcess.exe进程就消失了。少一个进程,也能节约不少内存。这个方法还是可以再完善的。

方法三:按方法二实现后,因为处理不完善,导致时有崩溃的情况发生。且方法一是比较完美的,因为QtWebEngine的十几个线程和至少40MB的内存占用,实在讨厌。那么,有什么办法可以实现呢?前面提到了子进程。但因为这里QWebEngineView是以子窗口形式存在,如果使用子进程,则又存在跨进程通信,跨进程的子窗口管理,还有弹窗等诸多问题,届时必定带来一堆bug。因此,子进程是下下之选。如果采用dll封装呢?

于是开始dll封装之路。我起初想的过于简单,没有写demo验证,直接修改。大量的代码修改,改了整整三天。然后测试。

第一个遇到的问题是,提示QWebEngine不能在dll中使用,如果一定要这样,得加上Qt::AA_ShareOpenGLContexts属性。按此要求修改。终于可以运行了,非常好。但是,当我卸载dll之后,Qt6WebEngineWidgets.dll和Qt6WebEngineCore.dll也卸载了,再之后,一个QTimer的事件回调处崩溃。查阅Qt代码后发现,QWebEngineMessagePumpScheduler里面不停地创建QTimer,而卸载后,这个QTimer没有回收,还会继续执行,其回调函数所在的dll已经卸载了,于是崩溃。那么,有没有办法呢?我试图给QApplication的notify重载,筛掉这个QTimer事件,但实在没有办法区分啊,objectName没有,虚函数表判断的话,感觉有点恶心了,如果这样处理。

至此,我才想到写个简单的demo验证,很显然,问题同上,也是同样的地方崩溃。

最终不得不放弃此想法。代码回退回原先的样子。

当然,后续还是考虑使用方法二,回收空闲的QWebEngineProfile,从而回收QtWebEngineProcess.exe进程。

 

转载请注明来源,谢谢。

有偿解决C++编程问题,承接项目定制开发;寻一份全职或兼职Windows C++开发工作。联系邮箱:[email protected]


老刀的技术日志 » Qt动态加载和卸载QWebEngine模块

发表评论