aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2024-01-05 19:06:05 +0100
committerUlf Hermann <ulf.hermann@qt.io>2024-01-11 00:42:17 +0100
commit953f0d44871b93a7a165e7026e48eaaadccf8d98 (patch)
treeef874e14059ee4ba958514fd7d98f5d1f0375ace /src/qml
parent809292e9b801fb5eb47dd7049bddc0fd776ab872 (diff)
QtQml: Clear stale compilation units more thoroughly
There are various places where we can still hold references. Clean them up when asked to do so. Also, free unused types and caches outside the type loader mutex, and only once on engine shutdown. Change-Id: Iae77cd6f50ad847d29a7eae4ac5c7c1c2524065d Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp11
-rw-r--r--src/qml/qml/qqmlengine.cpp10
-rw-r--r--src/qml/qml/qqmlmetatype.cpp53
-rw-r--r--src/qml/qml/qqmltypeloader.cpp1
4 files changed, 57 insertions, 18 deletions
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 769f9abd7e..c4ae949ea8 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -1518,9 +1518,18 @@ void QObjectWrapper::destroyObject(bool lastCall)
ddata->ownContext.reset();
ddata->context = nullptr;
}
- // This object is notionally destroyed now
+
+ // This object is notionally destroyed now. It might still live until the next
+ // event loop iteration, but it won't need its connections, CU, or deferredData
+ // anymore.
+
ddata->isQueuedForDeletion = true;
ddata->disconnectNotifiers(QQmlData::DeleteNotifyList::No);
+ ddata->compilationUnit.reset();
+
+ qDeleteAll(ddata->deferredData);
+ ddata->deferredData.clear();
+
if (lastCall)
delete o;
else
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index a5f6d4d531..b01c592316 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -623,9 +623,19 @@ QQmlEngine::~QQmlEngine()
void QQmlEngine::clearComponentCache()
{
Q_D(QQmlEngine);
+
+ // Contexts can hold on to CUs but live on the JS heap.
+ // Use a non-incremental GC run to get rid of those.
+ QV4::MemoryManager *mm = handle()->memoryManager;
+ auto oldLimit = mm->gcStateMachine->timeLimit;
+ mm->setGCTimeLimit(-1);
+ mm->runGC();
+ mm->gcStateMachine->timeLimit = std::move(oldLimit);
+
d->typeLoader.lock();
d->typeLoader.clearCache();
d->typeLoader.unlock();
+ QQmlMetaType::freeUnusedTypesAndCaches();
}
/*!
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 10b69cf850..a8995d9a4a 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -1535,6 +1535,27 @@ static bool hasActiveInlineComponents(const QQmlMetaTypeData *data, const QQmlTy
return false;
}
+static int doCountInternalCompositeTypeSelfReferences(
+ QQmlMetaTypeData *data,
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
+{
+ int result = 0;
+ auto doCheck = [&](const QtPrivate::QMetaTypeInterface *iface) {
+ if (!iface)
+ return;
+
+ const auto it = data->compositeTypes.constFind(iface);
+ if (it != data->compositeTypes.constEnd() && *it == compilationUnit)
+ ++result;
+ };
+
+ doCheck(compilationUnit->qmlType.typeId().iface());
+ for (auto &&inlineData: compilationUnit->inlineComponentData)
+ doCheck(inlineData.qmlType.typeId().iface());
+
+ return result;
+}
+
void QQmlMetaType::freeUnusedTypesAndCaches()
{
QQmlMetaTypeDataPtr data;
@@ -1543,6 +1564,21 @@ void QQmlMetaType::freeUnusedTypesAndCaches()
if (!data.isValid())
return;
+ bool droppedAtLeastOneComposite;
+ do {
+ droppedAtLeastOneComposite = false;
+ auto it = data->compositeTypes.begin();
+ while (it != data->compositeTypes.end()) {
+ if (!(*it)->engine
+ || (*it)->count() <= doCountInternalCompositeTypeSelfReferences(data, *it)) {
+ it = data->compositeTypes.erase(it);
+ droppedAtLeastOneComposite = true;
+ } else {
+ ++it;
+ }
+ }
+ } while (droppedAtLeastOneComposite);
+
bool deletedAtLeastOneType;
do {
deletedAtLeastOneType = false;
@@ -1931,22 +1967,7 @@ int QQmlMetaType::countInternalCompositeTypeSelfReferences(
const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
{
QQmlMetaTypeDataPtr data;
-
- int result = 0;
- auto doCheck = [&](const QtPrivate::QMetaTypeInterface *iface) {
- if (!iface)
- return;
-
- const auto it = data->compositeTypes.constFind(iface);
- if (it != data->compositeTypes.constEnd() && *it == compilationUnit)
- ++result;
- };
-
- doCheck(compilationUnit->qmlType.typeId().iface());
- for (auto &&inlineData: compilationUnit->inlineComponentData)
- doCheck(inlineData.qmlType.typeId().iface());
-
- return result;
+ return doCountInternalCompositeTypeSelfReferences(data, compilationUnit);
}
QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlMetaType::obtainExecutableCompilationUnit(
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 0abe3db316..07ec0038fb 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -1335,7 +1335,6 @@ void QQmlTypeLoader::clearCache()
m_importDirCache.clear();
m_importQmlDirCache.clear();
m_checksumCache.clear();
- QQmlMetaType::freeUnusedTypesAndCaches();
}
void QQmlTypeLoader::updateTypeCacheTrimThreshold()