CF для циклического использования памяти/процессора

Я пытаюсь заполнить кучу записей «случайными» данными, и все это для проверки удобства использования приложений с большим объемом данных.

Так что я, хотя - отлично! У меня есть свои методы для вставки, он выполняет некоторую «проверку дубликатов» и все такое. Все, что мне нужно сделать, это зациклить его x раз. И заполнить случайными значениями из БД.

Итак, я попадаю в БД один раз для каждого набора данных (три вещи в моем примере: пользователи, вещь1 и вещь2). Я делаю цикл и устанавливаю значения, которые хочу вставить случайным образом, и вызываю свою вставку...

Он работает нормально, примерно до 80-го цикла, затем он начинает замедляться, примерно до 180-го, вентиляторы процессора включаются на полную мощность, и CF расходуется ... Я пытался добавить команду «sleep» в конце каждого цикла, чтобы дать «чему бы то ни было» шанс решить, сделать это сборщиком мусора или чем-то еще.

Вот ошибка в журнале - "java.lang.OutOfMemoryError: превышен лимит накладных расходов GC"

Не большая удача. Может ли кто-нибудь дать мне некоторое представление об этом - у меня была идентичная проблема около 18 месяцев назад, проанализируйте некоторые карты. Я думал, что это просто потому, что итерации по «карточным рукам» были слишком обширными, и я согласился с этим.

Но это в основном 1000 операторов вставки, с вызовом и проверкой существующих записей перед каждым... это не должно быть огромной утечкой.?? должно ли это? - Не следует ли очищать каждую структуру данных в каждом цикле? и каждое соединение с базой данных будет освобождено, когда это будет сделано?

Я подозреваю, что «ответ» более теоретический и базовый, чем просто исправление «кода». Но мне действительно любопытно узнать, потому что это только поможет сделать любой будущий код более надежным.

Спасибо

Вот основная структура цикла.

// get master lists of all available data - will use for random selection
users  = createObject( 'component', 'users' ).getFullList;
thing1 = createObject( 'component', 'thing1' ).getFullList;
thing2 = createObject( 'component', 'thing2' ).getFullList;

for ( i = 1; i <= 1000; i++ ) {
    // get random id from within the recorset returned
    args = structNew();
    args['app_id'] = 1;
    args['user_id']   = users.id[RandRange( 1, users.recordcount , 'SHA1PRNG' )];
    args['thing1_id'] = thing1.id[RandRange( 1, thing1.recordcount , 'SHA1PRNG' )];
    args['thing2_id'] = thing2.id[RandRange( 1, thing2.recordcount , 'SHA1PRNG' )];

    // cehck for dups and put the data
    return = putData( argumentCollection = args );

    // tell me count and let me know if it succeeded
    writeoutput( '( #i# = #return# )' );

    // flush it - so I know where we are
    getPageContext().getOut().flush();

    // help garbage collection? something is causing a bog down
    structClear( args );
}

А вот и другие методы, вызываемые из объектов, созданных перед циклом. В цикле не создаются «лишние» компоненты — все это происходит один раз перед циклом.

/*
    methods from other components
*/

putData( [my arguments] ) {
    var isDuplicate = false;

    transaction action = 'begin' {
        // check for existing (dont allow dups)
        isDuplicate = chekForDuplicate( argumentcollection = arguments );

        if ( !isDuplicate ) {
            // deduct from users balance
            deduct = deductFromBalance(
                                        user_id = arguments.user_id
                                        ,units = 1
                                    );

            if ( deduct.success ) {
                try {
                    // put in users acct
                    insertData( argumentcollection = arguments );
                    transaction action = 'commit';
                    return true;
                } catch ( any e ) {
                    transaction action = 'rollback';
                    return false;
                }
            } else {
                transaction action = 'rollback';
                return false;
            }
        } else {
            transaction action = 'rollback';
            return false;
        }
    }
}

chekForDuplicate( [my arguments] ) {
    // check for uplicate
    var r = new Query(
        datasource = "myDSN"
        ,sql = "
            SELECT
                id
            FROM
                eventTable                  
            WHERE
                app_id = ?
            AND
                user_id = ?
            AND
                thing1_id = ?
            AND
                thing2_id = ?
        "
        ,parameters = [
                 { value = val( arguments.app_id ), cfsqltype = 'CF_SQL_INTEGER' }
                ,{ value = val( arguments.user_id ), cfsqltype = 'CF_SQL_INTEGER' }
                ,{ value = val( arguments.thing1_id ), cfsqltype = 'CF_SQL_INTEGER' }
                ,{ value = val( arguments.thing2_id ), cfsqltype = 'CF_SQL_INTEGER' }
        ]
    ).execute().getPrefix();

    if ( r.recordcount ) {
        return true;
    } else {
        return false;
    }
}


deductFromBalance( [myArgs] ) {
    var r = {};
        r['beginningBalance'] = checkBalance( arguments.user_id );
        r['unit'] = arguments.units;
        r['success'] = false;

        if ( r['beginningBalance'] > 0 ) {
            adjustBalance( argumentCollection = arguments );
        }

        r['endingBalance'] = checkBalance( arguments.user_id );

        if ( r['beginningBalance'] - r['endingBalance'] == r['unit'] ) {
            r['success'] = true;
        }

    return r;
}

checkBalance( [myArgs] ) {
    // return the balance for this user
    var r = new Query(
            datasource = 'myDSN'
            ,sql = "
                SELECT
                    balance
                FROM
                    users
                WHERE
                    id = ?
            "
            ,parameters = [
                { value = val( arguments.user_id ), cfsqltype = 'CF_SQL_INTEGER' }
            ]
        ).execute().getResult();

    return val( r.balance );
}

adjustBalance( [myArgs] ) {
    var r = false;
    var bal = checkBalance( arguments.user_id );

    if ( bal >= 0 && arguments.units > 0 ) {
        var q = new Query(
            datasource = 'myDSN'
            ,sql = "
                UPDATE
                    users
                SET
                    balance = ( balance + ? )
                WHERE
                    id = ?
            "
            ,parameters = [
                 { value = val( arguments.units ), cfsqltype = 'CF_SQL_INTEGER' }
                ,{ value = val( arguments.user_id ), cfsqltype = 'CF_SQL_INTEGER' }
            ]
        ).execute();

        r = true;
    }
    return r;
}

insertData( [myArgs] ) {
    // insert data
    var r = new Query(
            datasource = "myDSN"
            ,sql = "
                INSERT INTO
                    eventTable
                    (
                        app_id
                        ,user_id
                        ,thing1_id
                        ,thing2_id
                    )
                VALUES
                    (
                        ?
                        ,?
                        ,?
                        ,?
                    )
            "
            ,parameters = [
                 { value = val( arguments.app_id ), cfsqltype = 'CF_SQL_INTEGER' }
                ,{ value = val( arguments.user_id ), cfsqltype = 'CF_SQL_INTEGER' }
                ,{ value = val( arguments.thing1_id ), cfsqltype = 'CF_SQL_INTEGER' }
                ,{ value = val( arguments.thing2_id ), cfsqltype = 'CF_SQL_INTEGER' }
            ]
        ).execute().getPrefix();

    return r;
}

Все эти методы работают и возвращают то, что я ожидаю, поэтому, если я опечатал свою «аннотацию», пожалуйста, учтите это ... это потребление памяти или процессора, на котором я ищу входные данные.

Обновление 5 CF 11 для Win 7 — Core i7 4 ГБ ОЗУ Максимальный размер выходного буфера 2048 Минимальный размер кучи JVM 512 МБ Максимальный размер кучи JVM 1024 МБ


person j-p    schedule 18.08.2015    source источник
comment
Один из способов отладки — начать комментировать отдельные вызовы функций, перезапустить и посмотреть, сохраняется ли проблема. Так, например, сначала закомментируйте вызов putData(). Если проблема не устранена, закомментируйте вызов insertData. Промойте и повторите с другими вызовами функций.   -  person Sam M    schedule 18.08.2015
comment
И это, вероятно, не связано с вашей проблемой с памятью, но ваш deductFromBalance не защищен в попытке/улове, поэтому любое исключение там испортит состояние вашей транзакции.   -  person Sam M    schedule 18.08.2015
comment
@sam, я сделал это ... проблема, похоже, в методе insertData(). И спасибо за предложение попробовать/поймать   -  person j-p    schedule 18.08.2015
comment
сколько оперативной памяти вы выделили своему экземпляру CF? AFAIK CF не освобождает оперативную память, пока запрос не будет полностью обработан.   -  person Henry    schedule 18.08.2015
comment
@jpmyob - возможно, стоит взглянуть на эту тему . Это немного устаревший и немного другой базовый случай (массовая вставка, которую можно сделать гораздо эффективнее с другими инструментами), но некоторые из сообщений могут быть актуальными.   -  person Leigh    schedule 18.08.2015
comment
@leigh, да, мой следующий шаг - написать метод, который будет обрабатывать массовую вставку ... я пытался использовать существующий протестированный код, но одно массовое заполнение для тестирования - это решение. если бы это был процесс, который должен запускаться неоднократно, я был бы более склонен продолжать охоту... но на данный момент обходной путь - это решение.   -  person j-p    schedule 19.08.2015
comment
@henry - интересно - мне придется это исследовать. Я думаю, вы спрашиваете о моем выделении кучи JVM... которое я увеличил до 1024/2048, и это, похоже, не помогло   -  person j-p    schedule 19.08.2015
comment
@jpmyob - независимо от того, на что вы смотрите, зацикливание почти всегда неоптимально - в любом приложении. Особенно когда дело доходит до изменения данных. Зацикливание требует времени. Нет пути вокруг этого. По моему опыту, массовая вставка зачастую быстрее и проще в целом. Вместо того, чтобы применять сложную логику к каждой записи по отдельности, вы можете воспользоваться преимуществами операций на основе наборов — именно здесь базы данных действительно хороши. Таким образом, такие задачи, как поиск существующих/повторяющихся записей, часто бывают слишком сложными. проще и быстрее.   -  person Leigh    schedule 19.08.2015
comment
Зацикливание требует времени .. и ресурсов. Хотя я понимаю, что вышеизложенное не имеет прямого отношения к вашему первоначальному вопросу ... зацикливание на самом деле не лучший способ для вставки объемных данных IMO. CF просто не подходит для такого рода задач.   -  person Leigh    schedule 19.08.2015
comment
Если вам нужно использовать CF для вставок, не проверяйте дубликаты. Создайте временную таблицу и вставьте каждую запись. Это снижает активность внутри цикла. Как только записи будут в базе данных, используйте sql, чтобы сделать все остальное.   -  person Dan Bracuk    schedule 19.08.2015


Ответы (1)


Вы делаете слишком много работы внутри цикла. Я бы использовал этот подход.

Перед запуском цикла создайте временную таблицу в базе данных. Это должно быть временным, потому что вы должны признать возможность одновременной деятельности.

Внутри цикла просто создайте свои значения и вставьте их во временную таблицу. Хотя это и не идеально, вставка 1000 записей с помощью ColdFusion не является концом света. Я успешно делаю хуже.

Как только цикл завершится, используйте sql, чтобы сделать то, что вам нужно сделать с повторяющимися записями и другими проблемами с данными. Затем напишите в свою реальную таблицу базы данных из временной.

person Dan Bracuk    schedule 19.08.2015