LimeReport Forum
General Category | Основное => Discussion | Обсуждение => Topic started by: Dunkan on February 03, 2020, 10:38:21 am
-
Добрый день!
Замечена утечка в файле https://github.com/fralx/LimeReport/blob/master/limereport/lrreportengine.cpp (https://github.com/fralx/LimeReport/blob/master/limereport/lrreportengine.cpp) 1353-1356 строки.
-
Добрый день!
Чем проверяли?
-
Начинал с различных утилит по поиску утечек. Но в итоге пришлось искать вручную.
В конструктор TextItem добавил:
TextItem::TextItem( QObject *owner, QGraphicsItem *parent )
{
listLeak.append( this );
qDebug() << "create " << dynamic_cast<QObject *>( this ) << listLeak.size();
}
Где listLeak: static QList<QObject *> listLeak;
В деструктор:
TextItem::~TextItem()
{
listLeak.removeOne( this );
qDebug() << "delete" << dynamic_cast<QObject *>( this ) << listLeak.size();
}
Шло постоянное увеличение размеров listLeak, при каждом открытии отчета.
проверил так же в цикле, подтвердилось
for ( int i = 0; i < 100; i++ )
{
PreviewReportWidget *wdg = m_report->createPreviewWidget(); // где m_report = new LimeReport::ReportEngine()
delete wdg;
}
отчет довольно большой, около 70 объектов при каждом цикле терялось и чуть более 7мб оперативной памяти за все циклы.
Убрав комментарии с 1353-1355 строк:
//foreach(PageItemDesignIntf* page, m_renderingPages){
// delete page;
//}
проблема была успешно решена. Объекты теряться перестали, утечка уменьшилась с 7мб до чуть менее 1мб, возможно где то еще есть проблема, пока не могу найти.
Сможете также проверить данную проблему? Возможно я что-то где-то упускаю?
-
Все дело в том, что в лоб утечки в Qt детектировать не получается :(.
Qt имеет собственные механизмы выделения, кэширования и освобождения памяти.
//foreach(PageItemDesignIntf* page, m_renderingPages){
// delete page;
//}
Удаляет отрендеренные страницы, которые хранятся в шаредпоинтере и в прямом удалении не нуждаются, более того это противопоказано :)
Если предположить, что страницы не удаляются вовсе, то на каждом запуске рендера было бы кратное увеличение потребления памяти.
Наиболее достоверным способом измерения выделенной и освобожденной памяти является
замер кол-ва выделенной памяти до создания ReportEngine и после его освобождения (И даже в этом случае Qt может прикопать у себя часть памяти и перераспределить её позже).
-
Но как быть с тем что каждый вызов ReportEngine::createPreviewWidget() приводит к утечке объектов TextItem. Даже после удаления ReportEngine, часть созданных TextItem висят в памяти.
Простейший пример:
for ( int i = 0; i < 10; i ++ )
{
TestMemoryLeak();
}
void TestMemoryLeak()
{
QString path = "Путь до отчета";
LimeReport::ReportEngine *limereport = new LimeReport::ReportEngine();
limereport->loadFromFile( path );
auto prev = limereport->createPreviewWidget();
delete prev;
delete limereport;
}
-
Ок, проверю.
-
Вы оказались совершенно правы, спасибо :). Зависали шаблонные страницы.
Исправил, запушил.
-
Огромное спасибо! Сейчас пока разбираюсь с еще одной возможной утечкой, хотя это скорее даже не утечка, а исключительная ситуация, вкратце опишу свою мысль:
Имеется функция void ScriptEngineModel::updateModel()
, в которой используется следующее выражение m_rootNode->clear();
. Но т.к. m_rootNode создается в модели, которая хранится в классе типа Singlton, то при удалении ReportEngine и PreviewReportWidget m_rootNode с дочерними узлами остается в памяти, до завершения приложения. Но также был замечен рост кол-ва ScriptEngineNode почти с каждым новым циклом, а это уже становится похожим на утечку, использовал тот же тест что и выше, и проверял подобным способом:
static int countScriptEngineNode = 0;
ScriptEngineNode::ScriptEngineNode( const QString &name, const QString &description, NodeType type, ScriptEngineNode *parent, const QIcon &icon )
: m_name( name ), m_description( description ), m_icon( icon ), m_type( type ), m_parent( parent )
{
qDebug() << "create ScriptEngineNode " << this << ++countScriptEngineNode;
}
ScriptEngineNode::~ScriptEngineNode()
{
qDebug() << "delete ScriptEngineNode" << this << --countScriptEngineNode;
for ( int i = 0; i < m_childs.count(); ++i )
{
delete m_childs[i];
}
}
-
Ок. Тоже поковыряю :)
-
Поправил :) Пушнул :)
-
Благодарю!
Заметил что в новом коммите в функции
bool ScriptEngineManager::addFunction(const QString& name,
QScriptEngine::FunctionSignature function,
const QString& category,
const QString& description)
на строке 282 имеется вызов функции containsFunction, которая была удалена... а также обратите внимание на строку 291, там тоже идет ошибочка небольшая
-
Поправил, спасибо, что обратили моё внимание на этот косяк:)
QScriptEngine уже не использую вот и пропустил :)
-
Супер! =)