Commit 566be099 authored by Erik Verbruggen's avatar Erik Verbruggen Committed by Nikolai Kosjar

C++: Release more documents.

- fix memory leak in find-usages
- do not retain snapshot in search history
- when an editor is invisible for more than 2 minutes, release the
  backing snapshot

Retaining snapshots will retain their documents, and if done for too
long, the memory consumption might grow. This is especially the case
when switching to a different kit (Qt version): in that case, the new
versions of headers will be indexed, while the old ones stay around.

Task-number: QTCREATORBUG-5583
Task-number: QTCREATORBUG-7645
Task-number: QTCREATORBUG-9842

Change-Id: I045eda1565e0a3fa702baeffaab9c12662f90289
Reviewed-by: default avatarErik Verbruggen <erik.verbruggen@digia.com>
Reviewed-by: default avatarNikolai Kosjar <nikolai.kosjar@digia.com>
parent d58da4bd
......@@ -60,13 +60,12 @@ using namespace Utils;
FunctionDeclDefLinkFinder::FunctionDeclDefLinkFinder(QObject *parent)
: QObject(parent)
{
connect(&m_watcher, SIGNAL(finished()),
this, SLOT(onFutureDone()));
}
void FunctionDeclDefLinkFinder::onFutureDone()
{
QSharedPointer<FunctionDeclDefLink> link = m_watcher.result();
QSharedPointer<FunctionDeclDefLink> link = m_watcher->result();
m_watcher.reset();
if (link) {
link->linkSelection = m_scannedSelection;
link->nameSelection = m_nameSelection;
......@@ -256,7 +255,9 @@ void FunctionDeclDefLinkFinder::startFindLinkAt(
result->sourceFunctionDeclarator = funcDecl;
// handle the rest in a thread
m_watcher.setFuture(QtConcurrent::run(&findLinkHelper, result, refactoringChanges));
m_watcher.reset(new QFutureWatcher<QSharedPointer<FunctionDeclDefLink> >());
connect(m_watcher.data(), SIGNAL(finished()), this, SLOT(onFutureDone()));
m_watcher->setFuture(QtConcurrent::run(&findLinkHelper, result, refactoringChanges));
}
FunctionDeclDefLink::FunctionDeclDefLink()
......@@ -270,10 +271,6 @@ FunctionDeclDefLink::FunctionDeclDefLink()
targetFunctionDeclarator = 0;
}
FunctionDeclDefLink::~FunctionDeclDefLink()
{
}
bool FunctionDeclDefLink::isValid() const
{
return !linkSelection.isNull();
......
......@@ -67,7 +67,7 @@ private slots:
private:
QTextCursor m_scannedSelection;
QTextCursor m_nameSelection;
QFutureWatcher<QSharedPointer<FunctionDeclDefLink> > m_watcher;
QScopedPointer<QFutureWatcher<QSharedPointer<FunctionDeclDefLink> > > m_watcher;
};
class FunctionDeclDefLink
......@@ -75,8 +75,6 @@ class FunctionDeclDefLink
Q_DECLARE_TR_FUNCTIONS(CppEditor::Internal::FunctionDeclDefLink)
Q_DISABLE_COPY(FunctionDeclDefLink)
public:
~FunctionDeclDefLink();
class Marker {};
bool isValid() const;
......
......@@ -247,8 +247,9 @@ public:
CppFindReferences::CppFindReferences(CppModelManagerInterface *modelManager)
: QObject(modelManager),
_modelManager(modelManager)
m_modelManager(modelManager)
{
connect(modelManager, SIGNAL(globalSnapshotChanged()), this, SLOT(flushDependencyTable()));
}
CppFindReferences::~CppFindReferences()
......@@ -365,7 +366,7 @@ void CppFindReferences::findAll_helper(Find::SearchResult *search, CPlusPlus::Sy
this, SLOT(openEditor(Find::SearchResultItem)));
Find::SearchResultWindow::instance()->popup(IOutputPane::ModeSwitch | IOutputPane::WithFocus);
const CppModelManagerInterface::WorkingCopy workingCopy = _modelManager->workingCopy();
const CppModelManagerInterface::WorkingCopy workingCopy = m_modelManager->workingCopy();
QFuture<Usage> result;
result = QtConcurrent::run(&find_helper, workingCopy, context, this, symbol);
createWatcher(result, search);
......@@ -382,7 +383,7 @@ void CppFindReferences::onReplaceButtonClicked(const QString &text,
{
const QStringList fileNames = TextEditor::BaseFileFind::replaceAll(text, items, preserveCase);
if (!fileNames.isEmpty()) {
_modelManager->updateSourceFiles(fileNames);
m_modelManager->updateSourceFiles(fileNames);
Find::SearchResultWindow::instance()->hide();
}
}
......@@ -451,7 +452,7 @@ CPlusPlus::Symbol *CppFindReferences::findSymbol(const CppFindReferencesParamete
Document::Ptr newSymbolDocument = snapshot.document(symbolFile);
// document is not parsed and has no bindings yet, do it
QByteArray source = getSource(newSymbolDocument->fileName(), _modelManager->workingCopy());
QByteArray source = getSource(newSymbolDocument->fileName(), m_modelManager->workingCopy());
Document::Ptr doc =
snapshot.preprocessedDocument(source, newSymbolDocument->fileName());
doc->check();
......@@ -492,6 +493,7 @@ void CppFindReferences::searchFinished()
if (search)
search->finishSearch(watcher->isCanceled());
m_watchers.remove(watcher);
watcher->deleteLater();
}
void CppFindReferences::cancel()
......@@ -651,8 +653,8 @@ void CppFindReferences::findMacroUses(const Macro &macro, const QString &replace
connect(search, SIGNAL(cancelled()), this, SLOT(cancel()));
connect(search, SIGNAL(paused(bool)), this, SLOT(setPaused(bool)));
const Snapshot snapshot = _modelManager->snapshot();
const CppModelManagerInterface::WorkingCopy workingCopy = _modelManager->workingCopy();
const Snapshot snapshot = m_modelManager->snapshot();
const CppModelManagerInterface::WorkingCopy workingCopy = m_modelManager->workingCopy();
// add the macro definition itself
{
......@@ -691,6 +693,13 @@ DependencyTable CppFindReferences::updateDependencyTable(CPlusPlus::Snapshot sna
return newDeps;
}
void CppFindReferences::flushDependencyTable()
{
QMutexLocker locker(&m_depsLock);
Q_UNUSED(locker);
m_deps = DependencyTable();
}
DependencyTable CppFindReferences::dependencyTable() const
{
QMutexLocker locker(&m_depsLock);
......
......@@ -78,7 +78,10 @@ public:
CPlusPlus::DependencyTable updateDependencyTable(CPlusPlus::Snapshot snapshot);
private Q_SLOTS:
public slots:
void flushDependencyTable();
private slots:
void displayResults(int first, int last);
void searchFinished();
void cancel();
......@@ -101,7 +104,7 @@ private:
const CPlusPlus::Snapshot &snapshot, CPlusPlus::LookupContext *context);
private:
QPointer<CppModelManagerInterface> _modelManager;
QPointer<CppModelManagerInterface> m_modelManager;
QMap<QFutureWatcher<CPlusPlus::Usage> *, QPointer<Find::SearchResult> > m_watchers;
mutable QMutex m_depsLock;
......
......@@ -234,6 +234,11 @@ CppModelManager::CppModelManager(QObject *parent)
, m_indexingSupporter(0)
, m_enableGC(true)
{
connect(this, SIGNAL(documentUpdated(CPlusPlus::Document::Ptr)),
this, SIGNAL(globalSnapshotChanged()));
connect(this, SIGNAL(aboutToRemoveFiles(QStringList)),
this, SIGNAL(globalSnapshotChanged()));
m_findReferences = new CppFindReferences(this);
m_indexerEnabled = qgetenv("QTCREATOR_NO_CODE_INDEXER").isNull();
......
......@@ -279,6 +279,8 @@ signals:
/// Other classes can use this to get notified when the \c ProjectExplorer has updated the parts.
void projectPartsUpdated(ProjectExplorer::Project *project);
void globalSnapshotChanged();
public slots:
// Documented in source file.
virtual QFuture<void> updateSourceFiles(const QStringList &sourceFiles,
......
......@@ -41,6 +41,7 @@ SnapshotUpdater::SnapshotUpdater(const QString &fileInEditor)
, m_fileInEditor(fileInEditor)
, m_editorDefinesChangedSinceLastUpdate(false)
, m_usePrecompiledHeaders(false)
, m_forceSnapshotInvalidation(false)
{
}
......@@ -62,6 +63,11 @@ void SnapshotUpdater::update(CppModelManager::WorkingCopy workingCopy)
updateProjectPart();
if (m_forceSnapshotInvalidation) {
invalidateSnapshot = true;
m_forceSnapshotInvalidation = false;
}
if (m_projectPart) {
configFile += m_projectPart->defines;
includePaths = m_projectPart->includePaths;
......@@ -186,6 +192,14 @@ void SnapshotUpdater::update(CppModelManager::WorkingCopy workingCopy)
}
}
void SnapshotUpdater::releaseSnapshot()
{
QMutexLocker locker(&m_mutex);
m_snapshot = Snapshot();
m_deps = DependencyTable();
m_forceSnapshotInvalidation = true;
}
Document::Ptr SnapshotUpdater::document() const
{
QMutexLocker locker(&m_mutex);
......
......@@ -52,6 +52,7 @@ public:
{ return m_fileInEditor; }
void update(CppModelManagerInterface::WorkingCopy workingCopy);
void releaseSnapshot();
CPlusPlus::Document::Ptr document() const;
CPlusPlus::Snapshot snapshot() const;
......@@ -81,6 +82,7 @@ private:
CPlusPlus::Snapshot m_snapshot;
CPlusPlus::DependencyTable m_deps;
bool m_usePrecompiledHeaders;
bool m_forceSnapshotInvalidation;
};
} // namespace CppTools
......
......@@ -115,6 +115,7 @@ CppEditorSupport::CppEditorSupport(CppModelManager *modelManager, BaseTextEditor
, m_textEditor(textEditor)
, m_updateDocumentInterval(UpdateDocumentDefaultInterval)
, m_revision(0)
, m_editorVisible(textEditor->widget()->isVisible())
, m_cachedContentsEditorRevision(-1)
, m_fileIsBeingReloaded(false)
, m_initialized(false)
......@@ -152,6 +153,13 @@ CppEditorSupport::CppEditorSupport(CppModelManager *modelManager, BaseTextEditor
connect(m_textEditor->document(), SIGNAL(reloadFinished(bool)),
this, SLOT(onReloadFinished()));
connect(Core::EditorManager::instance(), SIGNAL(currentEditorChanged(Core::IEditor *)),
this, SLOT(onCurrentEditorChanged()));
m_editorGCTimer = new QTimer(this);
m_editorGCTimer->setSingleShot(true);
m_editorGCTimer->setInterval(EditorHiddenGCTimeout);
connect(m_editorGCTimer, SIGNAL(timeout()), this, SLOT(releaseResources()));
updateDocument();
}
......@@ -460,6 +468,30 @@ void CppEditorSupport::updateEditorNow()
editorWidget->setIfdefedOutBlocks(m_editorUpdates.ifdefedOutBlocks);
}
void CppEditorSupport::onCurrentEditorChanged()
{
bool editorVisible = m_textEditor->widget()->isVisible();
if (m_editorVisible != editorVisible) {
m_editorVisible = editorVisible;
if (editorVisible) {
m_editorGCTimer->stop();
QMutexLocker locker(&m_lastSemanticInfoLock);
if (!m_lastSemanticInfo.doc)
updateDocumentNow();
} else {
m_editorGCTimer->start(EditorHiddenGCTimeout);
}
}
}
void CppEditorSupport::releaseResources()
{
snapshotUpdater()->releaseSnapshot();
QMutexLocker semanticLocker(&m_lastSemanticInfoLock);
m_lastSemanticInfo = SemanticInfo();
}
SemanticInfo::Source CppEditorSupport::currentSource(bool force)
{
int line = 0, column = 0;
......
......@@ -148,6 +148,9 @@ private slots:
void updateEditor();
void updateEditorNow();
void onCurrentEditorChanged();
void releaseResources();
private:
struct EditorUpdates {
EditorUpdates()
......@@ -160,7 +163,8 @@ private:
enum {
UpdateDocumentDefaultInterval = 150,
UpdateEditorInterval = 300
UpdateEditorInterval = 300,
EditorHiddenGCTimeout = 2 * 60 * 1000 // 2 minutes
};
private:
......@@ -178,6 +182,9 @@ private:
unsigned m_revision;
QFuture<void> m_documentParser;
QTimer *m_editorGCTimer;
bool m_editorVisible;
// content caching
mutable QMutex m_cachedContentsLock;
mutable QByteArray m_cachedContents;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment