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>
This commit is contained in:
parent
cf28f909da
commit
23e0e26ce6
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
import QtQuick 2.2
|
||||
Rectangle
|
||||
{
|
||||
objectName: "dings"
|
||||
width: 100
|
||||
height: 100
|
||||
color: "blue"
|
||||
}
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue