aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2016-04-18 15:14:26 +0200
committerUlf Hermann <ulf.hermann@qt.io>2016-04-19 08:09:21 +0000
commit23e0e26ce652cf360310ebb1e2de8283502eba2e (patch)
treee07a5078f8021daca56ba7efca0b5f672e7b2f4a
parentcf28f909da1145b8f4fbb92a3bf8353d5f397f97 (diff)
Occasionally trim the type cache
As loaded components are kept in a cache, they are never removed by the garbage collector. So, if you periodically create new components, they leak. This change adds a floating threshold for the number of components. When that threshold is surpassed trimCache() is called and unneeded components are removed. Task-number: QTBUG-42055 Change-Id: I30e3e4ee287f6d34376713668009c67614a50e0c Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
-rw-r--r--src/qml/qml/qqmltypeloader.cpp20
-rw-r--r--src/qml/qml/qqmltypeloader_p.h2
-rw-r--r--tests/auto/qml/qqmltypeloader/data/trim_cache.qml8
-rw-r--r--tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp30
4 files changed, 59 insertions, 1 deletions
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 1e671542be..0e0efcf753 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -1113,6 +1113,7 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob)
}
#define DATALOADER_MAXIMUM_REDIRECT_RECURSION 16
+#define TYPELOADER_MINIMUM_TRIM_THRESHOLD 64
void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply)
{
@@ -1592,7 +1593,8 @@ bool QQmlTypeLoader::QmldirContent::designerSupported() const
Constructs a new type loader that uses the given \a engine.
*/
QQmlTypeLoader::QQmlTypeLoader(QQmlEngine *engine)
- : m_engine(engine), m_thread(new QQmlTypeLoaderThread(this))
+ : m_engine(engine), m_thread(new QQmlTypeLoaderThread(this)),
+ m_typeCacheTrimThreshold(TYPELOADER_MINIMUM_TRIM_THRESHOLD)
{
}
@@ -1629,6 +1631,10 @@ QQmlTypeData *QQmlTypeLoader::getType(const QUrl &url, Mode mode)
QQmlTypeData *typeData = m_typeCache.value(url);
if (!typeData) {
+ // Trim before adding the new type, so that we don't immediately trim it away
+ if (m_typeCache.size() >= m_typeCacheTrimThreshold)
+ trimCache();
+
typeData = new QQmlTypeData(url, this);
// TODO: if (compiledData == 0), is it safe to omit this insertion?
m_typeCache.insert(url, typeData);
@@ -1933,12 +1939,22 @@ void QQmlTypeLoader::clearCache()
qDeleteAll(m_importQmlDirCache);
m_typeCache.clear();
+ m_typeCacheTrimThreshold = TYPELOADER_MINIMUM_TRIM_THRESHOLD;
m_scriptCache.clear();
m_qmldirCache.clear();
m_importDirCache.clear();
m_importQmlDirCache.clear();
}
+void QQmlTypeLoader::updateTypeCacheTrimThreshold()
+{
+ int size = m_typeCache.size();
+ if (size > m_typeCacheTrimThreshold)
+ m_typeCacheTrimThreshold = size * 2;
+ if (size < m_typeCacheTrimThreshold / 2)
+ m_typeCacheTrimThreshold = qMax(size * 2, TYPELOADER_MINIMUM_TRIM_THRESHOLD);
+}
+
void QQmlTypeLoader::trimCache()
{
while (true) {
@@ -1963,6 +1979,8 @@ void QQmlTypeLoader::trimCache()
}
}
+ updateTypeCacheTrimThreshold();
+
// TODO: release any scripts which are no longer referenced by any types
}
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index 6433601ba8..f565bcd31f 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -358,6 +358,7 @@ private:
QQmlTypeLoaderThread *m_thread;
NetworkReplies m_networkReplies;
TypeCache m_typeCache;
+ int m_typeCacheTrimThreshold;
ScriptCache m_scriptCache;
QmldirCache m_qmldirCache;
ImportDirCache m_importDirCache;
@@ -365,6 +366,7 @@ private:
template<typename Loader>
void doLoad(const Loader &loader, QQmlDataBlob *blob, Mode mode);
+ void updateTypeCacheTrimThreshold();
friend struct PlainLoader;
friend struct CachedLoader;
diff --git a/tests/auto/qml/qqmltypeloader/data/trim_cache.qml b/tests/auto/qml/qqmltypeloader/data/trim_cache.qml
new file mode 100644
index 0000000000..74303977dd
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/trim_cache.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.2
+Rectangle
+{
+ objectName: "dings"
+ width: 100
+ height: 100
+ color: "blue"
+}
diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
index 4c5b1f7e63..7045c7cbd4 100644
--- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
+++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
@@ -35,6 +35,9 @@
#include <QtQml/qqmlengine.h>
#include <QtQuick/qquickview.h>
#include <QtQuick/qquickitem.h>
+#include <QtQml/private/qqmlengine_p.h>
+#include <QtQml/private/qqmltypeloader_p.h>
+#include <QtQml/private/qqmlcompiler_p.h>
#include "../../shared/util.h"
class tst_QQMLTypeLoader : public QQmlDataTest
@@ -44,6 +47,7 @@ class tst_QQMLTypeLoader : public QQmlDataTest
private slots:
void testLoadComplete();
void loadComponentSynchronously();
+ void trimCache();
};
void tst_QQMLTypeLoader::testLoadComplete()
@@ -73,6 +77,32 @@ void tst_QQMLTypeLoader::loadComponentSynchronously()
QVERIFY(o);
}
+void tst_QQMLTypeLoader::trimCache()
+{
+ QQmlEngine engine;
+ QQmlTypeLoader &loader = QQmlEnginePrivate::get(&engine)->typeLoader;
+ for (int i = 0; i < 256; ++i) {
+ QUrl url = testFileUrl("trim_cache.qml");
+ url.setQuery(QString::number(i));
+
+ QQmlTypeData *data = loader.getType(url);
+ if (i % 5 == 0) // keep references to some of them so that they aren't trimmed
+ data->compiledData()->addref();
+
+ data->release();
+ }
+
+ for (int i = 0; i < 256; ++i) {
+ QUrl url = testFileUrl("trim_cache.qml");
+ url.setQuery(QString::number(i));
+ if (i % 5 == 0)
+ QVERIFY(loader.isTypeLoaded(url));
+ else if (i < 128)
+ QVERIFY(!loader.isTypeLoaded(url));
+ // The cache is free to keep the others.
+ }
+}
+
QTEST_MAIN(tst_QQMLTypeLoader)
#include "tst_qqmltypeloader.moc"