Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум на CrossPlatform.RU _ Qt Script. Интеграция WebKit _ Постоянно течет память при исполнении скрипта

Автор: igor_bogomolov 6.9.2010, 17:34

Непрерывно течет память при исполнении скрипта. Кто сталкивался с подобным? Может я что то не правильно делаю?
За пример можно взять следующий код

bool Param::scriptEval()
{
    QString sFunction = QString(QLatin1String("function vparam(a,b,c,d,e) { return (e<<16) | a | b | c | d; }"));

    QScriptValue sv = scriptEngine->evaluate(sFunction);
    if (scriptEngine->hasUncaughtException()) {
        qDebug() << tr("Script for param '%1' error: '%2' for '%3'")
                   .arg(m_sName).arg(sv.toString()).arg(sFunction);
        return false;
    }

    QScriptValueList svlArgs;
    svlArgs << 0 << 0 << 0<< 0 << 1;

    QScriptValue fnObj = scriptEngine->globalObject().property(QLatin1String("vparam"));
    QScriptValue fnRes = fnObj.call(QScriptValue(), svlArgs);

    QString sResult = fnRes.toString();
    if (sResult.isEmpty()) {
        qDebug() << tr("Script for param '%1' returns NULL value string: %2")
                .arg(m_sName).arg(sFunction);
        return false;
    }

    qDebug() << sResult.toInt();

    return true;

Автор: kwisp 6.9.2010, 17:36

багтрекер троллей смотрел?

Автор: igor_bogomolov 6.9.2010, 18:51

Смотрел, конечно. Есть там такой баг http://bugreports.qt.nokia.com/browse/QTBUG-6426

Просто предполагаю, что я не правильно что то делаю. Не один же я скриптами пользуюсь, но не у нас ни на прогорге подобных жалоб не нашёл. К тому же стандартный пример context2d работает нормально. Там правда хитро как то, да и для моей задачи вреде таких сложностей и не нужно. Остальные стандартные примеры QtScript так же подтекают.

collectGarbage не помогает

Автор: Алексей1153 6.9.2010, 19:43

igor_bogomolov, а с какой строчки кода именно начинает появляться проблема ? (можно определить половинным заремариванием функции)

Автор: BRE 6.9.2010, 20:38

igor_bogomolov, проверь у себя этот код:

int main( int argc, char **argv )
{
    QCoreApplication app1( argc, argv );

    for( int i = 0; i < 100; ++i )
    {
        QScriptEngine scriptEngine;

        QString sFunction = QString( QLatin1String( "function vparam(a,b,c,d,e) { return (e<<16) | a | b | c | d; }" ) );
        QScriptValue sv = scriptEngine.evaluate( sFunction );
        if( scriptEngine.hasUncaughtException() )
        {
            qDebug() << "Script error";
            return 1;
        }

        QScriptValueList svlArgs;
        svlArgs << 0 << 0 << 0 << 0 << 1;

        QScriptValue fnObj = scriptEngine.globalObject().property( QLatin1String( "vparam" ) );
        QScriptValue fnRes = fnObj.call( QScriptValue(), svlArgs );

        QString sResult = fnRes.toString();
        if( sResult.isEmpty() )
        {
            qDebug() << "Script error";
            return 2;
        }

        qDebug() << sResult.toInt();
    }
    
    return 0;
}


Судя по выводу valgrind у меня ничего не течет.

Автор: igor_bogomolov 6.9.2010, 20:42

Цитата(Алексей1153 @ 6.9.2010, 20:43) *
а с какой строчки кода именно начинает появляться проблема ?

QScriptValue sv = scriptEngine->evaluate(sFunction);



BRE, спасибо, сейчас попробую.
А какоя у вас версия Qt?

Автор: BRE 6.9.2010, 20:45

Цитата(igor_bogomolov @ 6.9.2010, 21:42) *
BRE, спасибо, сейчас попробую.
А какоя у вас версия Qt?

$ qmake-qt4 --version
QMake version 2.01a
Using Qt version 4.6.3 in /usr/lib64

Автор: igor_bogomolov 6.9.2010, 22:07

Переделал немного таким образом

Раскрывающийся текст
#include <QtGui/QApplication>
#include <QtGui/QPushButton>
#include <QtCore/QDebug>
#include <QtScript/QScriptEngine>

class Test : public QObject
{
    Q_OBJECT
public slots:
    void evaluate() {
        for (int i=0; i!=1000;++i) {
            QString sFunction = QString( QLatin1String( "function vparam(a,b,c,d,e) { return (e<<16) | a | b | c | d; }" ) );
            QScriptValue sv = scriptEngine.evaluate( sFunction );
            if( scriptEngine.hasUncaughtException() )
            {
                qDebug() << "Script error";
                return;
            }

            QScriptValueList svlArgs;
            svlArgs << 0 << 0 << 0 << 0 << 1;

            QScriptValue fnObj = scriptEngine.globalObject().property( QLatin1String( "vparam" ) );
            QScriptValue fnRes = fnObj.call( QScriptValue(), svlArgs );

            QString sResult = fnRes.toString();
            if( sResult.isEmpty() )
            {
                qDebug() << "Script error";
                return;
            }

            qDebug() << sResult.toInt();
        }
    }
private:
    QScriptEngine scriptEngine;
};

#include "main.moc"

int main( int argc, char **argv )
{
    QApplication app( argc, argv );
    QPushButton button("text");

    Test test;

    QObject::connect(&button, SIGNAL(clicked()), &test, SLOT(evaluate()));

    button.show();
    return app.exec();
}

Valgrind можно сказать спокоен
"вывод valgrind"
Цитата
==13956== LEAK SUMMARY:
==13956== definitely lost: 124 bytes in 1 blocks
==13956== indirectly lost: 0 bytes in 0 blocks
==13956== possibly lost: 37,731 bytes in 530 blocks
==13956== still reachable: 135,512 bytes in 1,259 blocks
==13956== suppressed: 0 bytes in 0 blocks

Но в диспетчере задач, если нажимать на кнопочку, память постоянно растёт.

Я читал ваш комментарий по поводу диспетчера задач
Цитата
Память растет, потому что процесс запрашивает ее у ОС для своего хипа (кучи), но после освобождения памяти в хипе она не обязательно отдается системе обратно, а продолжает использоваться для аллокации внутри процесса. Поэтому, по диспетчеру и не видно ее освобождение.
В общем, диспетчер плохой инструмент для отлова утечек памяти внутри процесса.


Возможно диспетчер и плохой инструмент. Но память растёт непрерывно. За несколько дней начинает превышать 500 МБ и "планировщик" эту программу прибивает. Заказчик не доволен, т.к. программа должна работать непрерывно.

Возможно утечки есть и в другом месте. Сбивает то, что если я комментирую scriptEngine->evaluate утечки прекращаются.

Автор: Алексей1153 6.9.2010, 22:21

igor_bogomolov, как "быстрый костыль" можно попробовать засунуть сиё в отдельный процесс (если логика приложения позволяет).

А ещё - может быть, есть какой-нибудь метод для очистки памяти именно в объекте scriptEngine - его вызывать периодически.

В конце концов, как костыль сойдёт, наверное, периодическое пересоздание объекта scriptEngine через new (со всеми синхронизациями, естественно, если это нужно)

По крайней мере, это всё можно попробовать для убедиться, что дело именно в этом месте

Автор: DEADHUNT 6.9.2010, 22:21

==13956== definitely lost: 124 bytes in 1 blocks <--
==13956== indirectly lost: 0 bytes in 0 blocks
==13956== possibly lost: 37,731 bytes in 530 blocks <--

и это спокоен? запусти с флагом --leak-check=full

Автор: igor_bogomolov 6.9.2010, 22:45

Цитата(DEADHUNT @ 6.9.2010, 23:21) *
и это спокоен? запусти с флагом --leak-check=full

Запускал так.
Цитата
valgrind --leak-check=full --track-origins=yes --show-reachable=yes --log-file=1.txt ./script
Файл с выводом http://rghost.ru/2552575. Я не увидел там ничего криминального. Эти цифры постоянны и не зависят от того какое количество раз скрипт будет выполнен.

Да и поторопился я с предыдущим ответом. После n повторений, память расти перестает


Автор: DEADHUNT 6.9.2010, 22:50

да это утечки Qt, тоже их замечал.

Автор: ksth 18.2.2011, 14:39

Не уверен что поможет, но можно перед вызовом QScriptEngine::evaluate() делать pushContext (), а после popContext(). Насколько я понимаю данные имеют локальный характер, и возможно они увеличивают GlobalObject.

Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)