QPluginLoader::unload() returns false after deleting the plugin instance
0 reputation · 07 Nov 2022, 08:30 UTC
0 reputation · 07 Nov 2022, 08:30 UTC
I am designing a low-downtime update path for a small Qt 6 (C++) desktop application. The plan is to ship replaceable components as plugins loaded with QPluginLoader, unload the old plugin at runtime, swap the file, and load the new build — avoiding a full application restart.
After calling deleteLater() on the instance obtained from QPluginLoader::instance() and processing pending events, a subsequent call to QPluginLoader::unload() returns false, and the library stays loaded. Qt's documentation states unloading is only safe when no objects created from the plugin remain alive, but it is unclear which objects count: the root instance, child QObjects, QML types registered from the plugin, and metatype registrations may all keep the library pinned.
Target platforms include Windows, where a loaded DLL also cannot be overwritten on disk, so a failed unload blocks the whole file-swap strategy. The plugin registers custom metatypes and exposes one singleton-like object to the host.
33275 reputation · 07 Nov 2022, 11:21 UTC
The call to QPluginLoader::unload() fails because something created from the plugin’s binary is still alive or still referenced by the Qt type system. Until every such reference is released, the underlying OS will not free the library (on Windows the DLL remains locked).
QPluginLoader::instance() and all of its child QObjects keep the library mapped.new inside the plugin code also count, even if they are not parented to the root instance.qRegisterMetaType() or QML type registration create global entries in Qt’s type system that hold a reference to the plugin’s code segment; these registrations are not automatically undone when the instance is deleted.FreeLibrary, causing unload() to return false.unload() is opaque: it only tells whether the platform call succeeded, not which references remain.You delete the root instance with deleteLater() and process events, but the plugin also registers custom metatypes and exposes a singleton‑like object. Unless those metatype registrations are avoided or the singleton is destroyed and its references cleared, the type system still holds a reference to the plugin’s code, preventing unload.
instance() has no parent and is deleted.QCoreApplication::processEvents() or run the event loop) until the instance’s destroyed() signal is emitted.new‑ed objects you created manually).loader->unload(); it should return true on platforms where the library can be freed.If you have registered any custom metatypes or QML types from the plugin, the only reliable way to achieve near‑zero‑downtime updates is to use a process‑level handover (e.g., QLocalServer/QLocalSocket) rather than relying on QPluginLoader::unload(). Let me know whether your plugin performs such registrations so I can confirm if the handover pattern is needed.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.