yarkov
@yarkov
https://github.com/yarkovaleksei/toster-extension

Где здесь утечка памяти?

Господа! Ай нид хэлп!
Сил моих не осталось уже.
Пишу расширение для браузера. В общем отключил все что можно и оставил только один таймер.

Почти реальный пример кода. Методы класса вынесены в функции и убрана jQuery выборка.
// utils.js
export const getPage = ( url, _method = 'GET', _headers = {} ) => {
    const headers = new Headers();

    for ( const key in _headers ) {
        if ( {}.hasOwnProperty.call( _headers, key ) ) {
            headers.append( key, _headers[ key ] );
        }
    }

    headers.append( 'Pragma', 'No-cache' );
    headers.append( 'Cache-Control', 'No-cache' );

    const config = {
        method: _method,
        headers: headers,
        credentials: 'include',
        cache: 'no-store',
        client: 'no-window'
    };
    const f = fetch( url, config )
        .then( ( response ) => {
            if ( response.status >= 200 && response.status < 300 ) {
                return Promise.resolve( response );
            }
            return Promise.reject( new Error( response.statusText ) );
        } )
        .then( response => response.text() )
        .catch( console.error );
    return f;
};


// background.js
import { getPage } from './utils';

let Timer = null;
let useNotificationsFlag = 0;
const tracker_url = 'https://toster.ru/my/feed';
const Options = {};

const checkNotify = () => {
    window.promise = getPage( tracker_url );
    window.promise.then( ( body ) => {
            // В body лежит html страницы Тостера
            // Работаем с помощью jQuery, делаем выборку и считаем количество элементов
            // Обновляем иконку расширения

            body = null;
            return Promise.resolve();
        } )
        .then( () => ( window.promise = null ) );
}

const stopTimer = () => {
    clearTimeout( Timer );
    window.promise = null;
}

const reStartTimer = () => {
    stopTimer();
    startTimer();
}

const startTimer = () => {
    if ( !Options.check_notify || ( Options.interval < 1 ) ) {
        return false;
    }

    Timer = setTimeout( () => checkNotify(), Options.interval * 1000 );
}

startTimer();


В общем если вызывать reStartTimer() каждые 5-10 секунд, то съедаемая память растет на 400-600 Кб с каждым запросом.
В итоге расширение отжирает гигантское количество памяти и падает (((
Я уже всю башку сломал...
  • Вопрос задан
  • 1904 просмотра
Пригласить эксперта
Ответы на вопрос 2
dummyman
@dummyman
диссидент-схизматик
Во первых, вы неправильно используете анонимные функции, например
const startTimer = (){ ... }
и все остальные.
Анонимные функции можно использовать только в ситуациях, когда их вызывают "не по имени" для сохранения контекста. Например, аргументом forEach().
В данной ситуации лучшей синтаксической формы ничего не придумали:
function startTimer(){ ... }
Второй момент
for ( const key in _headers ) {
        if ( {}.hasOwnProperty.call( _headers, key ) ) {
            headers.append( key, _headers[ key ] );
        }
    }

и конкретно
if ( {}.hasOwnProperty.call( _headers, key ) )
Вы в цикле каждой итерацией создаете новый объект, это крайне не рациональное использование метода hasOwnProperty()
по мне
if (_headers != null && !!_headers[key] )
может выглядело бы не так красиво, за то потребляет памяти по-меньше.
Третий момент
.catch( console.error )
Вы можете немного сэкономить памяти использовав как раз по назначению анонимную функцию
.catch( e => console.error(e) )
В этом случае интерпритатор не будет искать ссылку на console.error при создании каждого промиса, и будет искать, соответственно, только в исключитальных ситуациях.
Четвертый момент
Поменьше пользуйтесь ключевым словом const, особенно, внутри методов и функций. Во-первых, так как они не выгружаются из памяти. Во вторых, const не дает никаких преимуществ в производительности, только лишь накладывает на интерпритатор обязанности следить чтобы ее случайно не перегрузили.
Ответ написан
akzhan
@akzhan
Проверьте на всякий случай, что у вас в любом случае вызывается response.text() или аналоги. Если не вызовется, возможен memory leak как минимум в V8.

А вообще в Chrome же можно делать снимки кучи.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы