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