From 8f131a2f310cfcff9bd39bc51317cdcf450460a6 Mon Sep 17 00:00:00 2001 From: xiepengfei Date: Fri, 10 Apr 2026 13:45:41 +0800 Subject: [PATCH] fix: prevent crashes and memory leaks during object lifecycle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add batch update flag to suppress intermediate signals during page navigation, add null checks for parent private pointer in DccObject, and fix component memory leaks when plugin manager is deleting. 添加批量更新标志以抑制页面导航期间的中间信号发射, 增加 DccObject 父对象私有指针的空检查,修复插件管理器 删除时的组件内存泄漏问题。 Log: 修复对象生命周期中的崩溃和内存泄漏问题 PMS: BUG-335919 Influence: 修复控制中心页面切换过程中可能出现的崩溃问题, 修复插件卸载时的内存泄漏,提升稳定性。 --- src/dde-control-center/dccmanager.cpp | 5 +++++ src/dde-control-center/dccmanager.h | 4 ++++ src/dde-control-center/plugin/DccLoader.qml | 11 +++++++++-- src/dde-control-center/plugin/dccapp.h | 4 +++- src/dde-control-center/plugin/dccobject.cpp | 20 +++++++++++++------- src/dde-control-center/pluginmanager.cpp | 9 +++++++++ 6 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/dde-control-center/dccmanager.cpp b/src/dde-control-center/dccmanager.cpp index fbfbe67f1b..08604423e7 100644 --- a/src/dde-control-center/dccmanager.cpp +++ b/src/dde-control-center/dccmanager.cpp @@ -837,6 +837,8 @@ void DccManager::doShowPage(QPointer obj, const QString &cmd) if (triggeredObj->pageType() == DccObject::MenuEditor && !triggeredObj->getChildren().isEmpty()) { triggeredObj = triggeredObj->getChildren().first(); } + + m_batchUpdating = true; DccObject *tmpObj = triggeredObj; tmpObj->setCurrentObject(nullptr); tmpObj->active(QString()); @@ -850,6 +852,7 @@ void DccManager::doShowPage(QPointer obj, const QString &cmd) tmpObj = tmpObjParent; } if (!tmpObj) { + m_batchUpdating = false; return; } modules.append(tmpObj); @@ -881,6 +884,8 @@ void DccManager::doShowPage(QPointer obj, const QString &cmd) // 更新当前对象 m_currentObjects = modules; m_triggeredObjects = triggeredObjs; + m_batchUpdating = false; + Q_EMIT triggeredObjectsChanged(m_triggeredObjects); if (auto *lastObj = m_currentObjects.last(); lastObj != m_activeObject) { m_activeObject = lastObj; diff --git a/src/dde-control-center/dccmanager.h b/src/dde-control-center/dccmanager.h index 77e8e89296..502ff6a579 100644 --- a/src/dde-control-center/dccmanager.h +++ b/src/dde-control-center/dccmanager.h @@ -12,6 +12,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE class QWindow; @@ -52,6 +53,8 @@ class DccManager : public DccApp, protected QDBusContext inline const QVector &triggeredObjects() const override { return m_triggeredObjects; } + inline bool isBatchUpdating() const override { return m_batchUpdating; } + Q_INVOKABLE DccApp::UosEdition uosEdition() const; Q_INVOKABLE Dtk::Core::DSysInfo::ProductType productType() const; @@ -145,6 +148,7 @@ private Q_SLOTS: QDBusMessage m_showMessage; QHash> m_objMap; // 映射对象名称到对象指针列表,用于快速查找 + std::atomic m_batchUpdating{false}; }; } // namespace dccV25 #endif // DCCMANAGER_H diff --git a/src/dde-control-center/plugin/DccLoader.qml b/src/dde-control-center/plugin/DccLoader.qml index 0ddb3afcd1..b9b01b55f2 100644 --- a/src/dde-control-center/plugin/DccLoader.qml +++ b/src/dde-control-center/plugin/DccLoader.qml @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 - 2027 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. // SPDX-License-Identifier: GPL-3.0-or-later import QtQuick @@ -7,10 +7,17 @@ Loader { property Item dccObjItem: null function updateDccObjItem() { - if (dccObj) { + if (dccObj && dccObjItem) { dccObj.parentItem = dccObjItem } } + + Component.onDestruction: { + if (dccObj && dccObj.parentItem === dccObjItem) { + dccObj.parentItem = null + } + } + enabled: dccObj && dccObj.enabledToApp // asynchronous: true sourceComponent: dccObj ? dccObj.page : null diff --git a/src/dde-control-center/plugin/dccapp.h b/src/dde-control-center/plugin/dccapp.h index e29519ea70..03ededa473 100644 --- a/src/dde-control-center/plugin/dccapp.h +++ b/src/dde-control-center/plugin/dccapp.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 - 2027 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later #ifndef DCCAPP_H @@ -62,6 +62,8 @@ class DccApp : public QObject virtual void setSidebarWidth(int width); virtual void setAnimationMode(AnimationMode mode); + virtual bool isBatchUpdating() const { return false; } + public Q_SLOTS: virtual DccObject *object(const QString &name); virtual void addObject(DccObject *obj); diff --git a/src/dde-control-center/plugin/dccobject.cpp b/src/dde-control-center/plugin/dccobject.cpp index c223bb00b6..24c885f5d4 100644 --- a/src/dde-control-center/plugin/dccobject.cpp +++ b/src/dde-control-center/plugin/dccobject.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "dccobject.h" +#include "dccapp.h" #include "dccobject_p.h" #include @@ -45,7 +46,7 @@ DccObject::Private::~Private() m_page->deleteLater(); m_page = nullptr; } - if (m_parent) { + if (m_parent && m_parent->p_ptr) { m_parent->p_ptr->removeChild(q_ptr); } while (!m_children.isEmpty()) { @@ -177,7 +178,7 @@ const QVector &DccObject::Private::getChildren() const int DccObject::Private::getIndex() const { - return m_parent ? m_parent->p_ptr->getChildren().indexOf(q_ptr) : -1; + return (m_parent && m_parent->p_ptr) ? m_parent->p_ptr->getChildren().indexOf(q_ptr) : -1; } DccObject *DccObject::Private::getChild(int childPos) const @@ -295,7 +296,7 @@ void DccObject::setWeight(quint32 weight) { if (p_ptr->m_weight != weight) { p_ptr->m_weight = weight; - if (p_ptr->m_parent) { + if (p_ptr->m_parent && p_ptr->m_parent->p_ptr) { p_ptr->m_parent->p_ptr->updatePos(this); } Q_EMIT weightChanged(p_ptr->m_weight); @@ -442,11 +443,16 @@ DccObject *DccObject::currentObject() void DccObject::setCurrentObject(DccObject *obj) { if (p_ptr->m_currentObject != obj) { - if (p_ptr->m_currentObject) { - Q_EMIT p_ptr->m_currentObject->deactive(); - } + DccObject *oldObject = p_ptr->m_currentObject; p_ptr->m_currentObject = obj; - Q_EMIT currentObjectChanged(p_ptr->m_currentObject); + + DccApp *app = DccApp::instance(); + if (!app || !app->isBatchUpdating()) { + if (oldObject) { + Q_EMIT oldObject->deactive(); + } + Q_EMIT currentObjectChanged(p_ptr->m_currentObject); + } } } diff --git a/src/dde-control-center/pluginmanager.cpp b/src/dde-control-center/pluginmanager.cpp index 515206412a..6256aa0cec 100644 --- a/src/dde-control-center/pluginmanager.cpp +++ b/src/dde-control-center/pluginmanager.cpp @@ -151,6 +151,13 @@ void LoadPluginTask::createData() soObj->setParent(nullptr); } } + if (m_pManager->isDeleting()) { + if (dataObj) + delete dataObj; + if (soObj) + delete soObj; + return; + } if (dataObj) { m_data->data = dataObj; } @@ -507,6 +514,7 @@ void PluginManager::loadMain(PluginData *plugin) void PluginManager::createModule(QQmlComponent *component) { if (isDeleting()) { + component->deleteLater(); return; } PluginData *plugin = component->property("PluginData").value(); @@ -536,6 +544,7 @@ void PluginManager::createModule(QQmlComponent *component) void PluginManager::createMain(QQmlComponent *component) { if (isDeleting()) { + component->deleteLater(); return; } PluginData *plugin = component->property("PluginData").value();