PDA

Просмотр полной версии : Firefox + LoadVars + SetInterval = Пожирание CPU (CPU hog)


unix0id
14.07.2010, 06:15
Мое почтение,
Заранее прошу прощения если что не так оформлено или написано, это мой первый пост. На форумах никогда не писал, обычно читал и анализировал информацию.
Но тут дело серьезное, бьюсь над проблемой уже неделю перелопатил не один форум в.т.ч англоязычные результат близкий к нулевому.
Итак собственно к сути. Я Разрабатываю приложение для контакта. Некая смесь MMORPG и Шахмат Online (На самом деле приложение уже работает и одобренно администрацией контакта). Приложение достаточно комфортно себя чувствует в браузерах(IE, Opera, Google, Chrom)
НО, в Firefox творится что-то невероятное... за 5-6 минут игра съедает процессор под 100% и становится не то что невозможно играть, но даже проблемно закрыть браузер.
Сначала я грешил на утечку памяти (memory leaks) перепроверил все ф-ции подчистил все NEW обьекты delet'ом. не помогает... CPU кушается за милую душу
После долгих мытарств установил что память не кушается если убрать из всех активных интервалов LoadVariables или LoadVars
(Под активными интервалами имею в виду - интервалы отвечающие за сетевое взаимодействие т.е. все время выполняют одну и ту же задачу, например отправляют Alive пакеты на сервер каждую секунду для того чтобы показасть что пользователь онлайн)
Т.Е. установил что Firefox начинает подъедать CPU только если происходит частое сетевое взаимодействие (частое: 1 пекет на отправку 4 на получение в секунду)

Для проверки создал пустое приложение в него запихнул 2 интервала в каждом интервале написал выполнение 1ого loadvars (с кодом по типу приведенного ниже). за пол часа данный скрипт съел 70% CPU
Ниже привожу пример исользуемого мной куска кода с 1им циклом. для примера оформления... может заметите что-то что может грузить CPU или вызывать утечки памяти.

//Ф-ция опроса ячейки чата
function logsLoaded() {
//грузим данные с SQL
var chatvar:LoadVars = new LoadVars();
chatvar.load("http://www.site.com/?cmd=get1&game_id="+_global.game_id+"&id=11&f="+_global.battleType+"&time="+getTimer());
chatvar.onLoad = function(success) {
// загрузили
if (success) {
//если есть данные выводим их в окне чата
if (chatvar.firstPerson != undefined) {
_global.lastcharacter = chatvar.firstPerson;
// для того чтобы не выводить повторяющиеся сообщения
if (_global.lastcharacter != _global.prelast) {
_global.prelast = _global.lastcharacter;
_root.chat_txt = "<font color='#000000'><b>DEMO MODE: '"+chatvar.firstPerson+"'</b></font>\n"+_root.chat_txt;
//очищаем new
delete chatvar;
} else {
//очищаем new деже если не загр
delete chatvar;
}
}
}
};
//паранойно чистим все что можно от mem leaks
//для того чтобы перебдеть и очистить на всякий случай интервал использую следующую конструкцию
delete chatvar;
clearInterval(_global.logs_interval);
delete _global.logs_interval;
_global.logs_interval = setInterval(logsLoaded, 1200);
_global.ClearLogsInt =Number (_global.ClearLogsInt+1) ;
_root.chat_txt = _global.ClearLogsInt;

}
// первый запуск ф-ции в цикл
_root.logsLoaded();


Напомню что данная проблема только в Firefox. а другие браузеры работают норм... У меня соят Флеш и Файерфокс самые последние. на других компьютерах с более старыми версиями тоже самое. Очень прошу всех кто понимает о чем речь или испытывал подобные проблемы отозваться. Помогите разобраться как решить проблему, проект гибнет ! 6 мес работы на смарку. могу дать ссылку на рабочий проект в контакте. И куски исходников тем кто в состоянии помочь. Готов проставиться за адекватную помощь :drinks:(СПб). Да что там, готов заплатить если помогут эксперты.

alexcon314
14.07.2010, 09:01
Что явно нехорошо:
- вложенная функция "chatvar.onLoad = function(success){...}", она создается вновь (с выделением нового куска памяти, естественно) при каждом вызове logsLoaded();
- кусок кода
delete chatvar;
clearInterval(_global.logs_interval);
delete _global.logs_interval;
_global.logs_interval = setInterval(logsLoaded, 1200);
_global.ClearLogsInt =Number (_global.ClearLogsInt+1) ;
_root.chat_txt = _global.ClearLogsInt;
выполняется ДО загрузки лоадварса - так и задумано, т.е. вы как бы "удаляете" chatvar, а потом в него падают пришедшие данные?
- зачем чистить интервал и тут же назначать его вновь, удалять переменную и тут же создавать вновь? это не паранойя, а маразм;
- сомневаюсь, что ваши delete работают в любом случае, ибо вы сохраняете ссылки на объект в глобал-переменную прежде чем удалить.
И что, это нормально работает везде, кроме ФФ?
Потом, что вы здесь называете циклом? Вызв по интервалу? Так и сделайте нормальный 1 (один единственный) интервал, без вложенных функций, без ненужных ссылок в глобал и прочей фигни.
function onLoadHandler(success){
if(success){
...
}
else{
...
}
}
var lv:LoadVars = new LoadVars();
lv.onLoad = onLoadHandler;
function loggsLoaded(){
lv.load(...);
}
var intv = setInterval(loggsLoaded,1200);

unix0id
14.07.2010, 15:44
alexcon314 - Спасибо огромное за развернутый ответ.

Что самое смешное неделю назад у меня была подобная Вашей конструкция. До того, как я в целях паранои начал бороться с утечками памяти. =)

Сейчас опробую Вашу конструкцию и обязательно отпишусь по результатам...
Еще раз спасибо.
P.S. - А CPU действительно утекает только в файерфоксе.

Добавлено через 3 часа 47 минут
воспользовался конструкцией приведенной выше, не помогло... Для того чтобы не быть голословным приведу пример на базе кода приведенного выше...
для тестов создал пустое приложение со следующим кодом:

//Тестовая конструкция для проверки учечки CPU (3 интервала с LOADVARS)
// 1й интервал
function onLoadHandler(success) {
if (success) {
// посто счетчик количества исполнений для наглядности
_root.chat_txt = Number (_root.chat_txt + 1) ;

} else {

}
}
var chatvar:LoadVars = new LoadVars();
chatvar.onLoad = onLoadHandler;

function loggsLoaded() {
chatvar.load("http://site.com/gametest/?cmd=get1&game_id="+_global.game_id+"&id=11&f="+_global.battleType+"&time="+getTimer());
}
var chatInterval = setInterval(loggsLoaded, 500);



// Для увеличения нагрузки и наглядности делаю 2е копии интервалов
// 2й интервал
function onLoadHandler2(success) {
if (success) {
_root.chat_txt2 = Number (_root.chat_txt2 + 1) ;

} else {

}
}
var chatvar2:LoadVars = new LoadVars();
chatvar2.onLoad = onLoadHandler2;

function loggsLoaded2() {
chatvar2.load("http://site.com/gametest/?cmd=get1&game_id="+_global.game_id+"&id=11&f="+_global.battleType+"&time="+getTimer());
}

var chatInterval2 = setInterval(loggsLoaded2, 1000);

// 3й интервал
function onLoadHandler3(success) {
if (success) {
_root.chat_txt3 = Number (_root.chat_txt3 + 1) ;

} else {

}
}
var chatvar3:LoadVars = new LoadVars();
chatvar3.onLoad = onLoadHandler3;

function loggsLoaded3() {
chatvar3.load("http://site.com/gametest/?cmd=get1&game_id="+_global.game_id+"&id=11&f="+_global.battleType+"&time="+getTimer());
}

var chatInterval3 = setInterval(loggsLoaded3, 1500);


результатом 15и мнутной работы в опере утечки CPU не наблюдалось см скриншот1

http://otvertka.com/mem/mem_opera.gif

тот же скрипт в firefox спосебен убить машину за 20 мин... я не стал дожидаться этого просто показал что процессор пожирается...
см скриншот 2
http://otvertka.com/mem/mem_ff.gif

наглядно видно что процессор медленно но верно умирает... проверил еще на 2х компьютерах результат одинаков ff умирает остальные прекрасно работают...
:eek:
может что не замечаю?
Господа помогите разобраться кто виноват и что делать?

in4core
15.07.2010, 00:01
Виноват билгейтс, делать - снести виндовс ))) Ну вот такой вот фаерфокс жрущий ниче тут не сджелаешь

rainbowrussia
15.07.2010, 02:40
Создал пустой проект, вставил в кадр ваш последний код, заменил site.com на свой домен со ссылкой на существующий файл + timer. FirefoxPortable 3.0.5, память не растет, процессор не загружается. Создайте полноценный проект на основе вашего последнего кода (для CS3), убедитесь что он ест память и выложите, я проверю у себя и попробую посмотреть что к чему.

unix0id
15.07.2010, 03:23
Создал пустой проект, вставил в кадр ваш последний код, заменил site.com на свой домен со ссылкой на существующий файл + timer. FirefoxPortable 3.0.5, память не растет, процессор не загружается. Создайте полноценный проект на основе вашего последнего кода (для CS3), убедитесь что он ест память и выложите, я проверю у себя и попробую посмотреть что к чему.

Очень Вам признателен за желание помочь.
Для начала я скачал на пробу Ваш FF 3.0.5 Portable - протестировал, результат тот же. Для Всех интересующихся создал и выложил даный исходник (http://otvertka.com/mem/ff-fps.fla) (.fla Flash8 (AS2)) и скомпилированную SWF'ку (http://otvertka.com/mem/ff-fps.swf) данная SWFка за 15-20 мин отъедает до 100 CPU на 3х машинах на которых удалось проверить. Вуду признателен за любые коментарии и оценки

rainbowrussia
15.07.2010, 05:56
Попробуйте следующий код:


_root.loaded1 = 1;
_root.loaded2 = 1;
_root.loaded3 = 1;

//Тестовая конструкция для проверки учески CPU (3 интервала с LOADVARS)
// 1й интервал
function onLoadHandler(success) {
_root.loaded1 = 1;
if (success) {
_root.chat_txt = Number (_root.chat_txt + 1) ;

} else {

}
}
var chatvar:LoadVars = new LoadVars();
chatvar.onLoad = onLoadHandler;

function loggsLoaded() {
if (_root.loaded1 == 0) { return; }
_root.loaded1 = 0;
chatvar.load("http://otvertka.com/gametest/?cmd=get1&game_id="+_global.game_id+"&id=11&f="+_global.battleType+"&time="+getTimer());
}
var chatInterval = setInterval(loggsLoaded, 500);



// Для увеличения нагрузки и наглядности делаю 2е копии интервалов
// 2й интервал
function onLoadHandler2(success) {
_root.loaded2 = 1;
if (success) {
_root.chat_txt2 = Number (_root.chat_txt2 + 1) ;

} else {

}
}
var chatvar2:LoadVars = new LoadVars();
chatvar2.onLoad = onLoadHandler2;

function loggsLoaded2() {
if (_root.loaded2 == 0) { return; }
_root.loaded2 = 0;
chatvar2.load("http://otvertka.com/gametest/?cmd=get1&game_id="+_global.game_id+"&id=11&f="+_global.battleType+"&time="+getTimer());
}

var chatInterval2 = setInterval(loggsLoaded2, 1000);

// 3й интервал
function onLoadHandler3(success) {
_root.loaded3 = 1;
if (success) {
_root.chat_txt3 = Number (_root.chat_txt3 + 1) ;

} else {

}
}
var chatvar3:LoadVars = new LoadVars();
chatvar3.onLoad = onLoadHandler3;

function loggsLoaded3() {
if (_root.loaded3 == 0) { return; }
_root.loaded3 = 0;
chatvar3.load("http://otvertka.com/gametest/?cmd=get1&game_id="+_global.game_id+"&id=11&f="+_global.battleType+"&time="+getTimer());
}

var chatInterval3 = setInterval(loggsLoaded3, 1500);


Здесь введены переменные плюс код, предотвращающий загрузку данных до тех пор пока предыдущий запрос не будет выполнен. У меня этот код (с другим адресом загрузки данных, так как ваш позволяет загружать только контакту) не вызвал роста CPU, попробуйте у себя. Если код заработает - значит надо решать проблему с медленной загрузкой данных - либо так же не загружать следующую порцию, пока не загрузилась предыдущая, либо как-то иначе, возможно, уничтожая объекты LoadVars и создавая новые.

unix0id
16.07.2010, 02:16
Господа, alexcon314 и rainbowrussia я крайне признателен Вам за отклик на мой зов помощи. Если Вы живете в Петербурге или будете проездом буду рад угостить Вас холодненьким и составить приятную компанию... (если предложение принимается стукните в личку, скину свои контакты)
А теперь собственно о корне зла... ответ rainbowrussia натолкнул меня на мысль о том что причиной утечки может быть не только Flash и Firefox (хотя это может показаться очевидным на первый взгляд) , но и серверная часть, ведь у rainbowrussia (извините, не знаю имени) на его сервере тот же код работает нормально... Результатом анализа серверной части стало: Утечку CPU вызывает одна строчка в конфиге nginx (Для тех кто не знает это http сервер, аналог Апача но более быстрый по ряду причин)
Собственно строчка уже измененная и настроенная на правильную работу конфига выглядит так:

gzip off

оказалось что файерфокс в силу каких-то своих внутренних особенностей очень много времени тратит на распаковку закапсюлированных сетевых пакетов... тем самым загружает CPU
После отключения архивации сетевых пакетов проблема ушла.
Еще раз всем спасибо. Надеюсь данный пост спасет еще пару потерявших сон людей. =)

rainbowrussia
16.07.2010, 02:45
Есть опасение что проблема не в gzip-е. Если бы проблема была только в распаковке данных, то загрузка CPU не росла бы, а просто была бы чуть выше (незаметно даже) чем при gzip off.

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

Вы мой вариант на своем сервере запускали? Загрузка CPU росла?

unix0id
16.07.2010, 03:02
да, файлы тестировал и Ваш и свой запускал. Сразу после отключения данной строчки пропало поедание CPU и в наших файлах и даже в самом приложении в контакте (http://vkontakte.ru/app1875464_70844082). Это подтверждает и тот факт что память поедал сам firefox а не plugin-контейнер установленный в последней версии файерфокса. А на счет холодненького :drinks: предложение в силе :)

rainbowrussia
16.07.2010, 04:00
А на счет холодненького :drinks: предложение в силе :)
Далековато :) Но полюбому спасибо.
Будет время, попробуйте поюзать ваше приложение через какой-нибудь далекий и медленный прокси-сервер, дабы убедиться что дело не в задержке при передачи данных.

unix0id
16.07.2010, 17:19
Ок, спасибо, поставил этот тест в планах

dimarik
17.07.2010, 17:23
зачем keep alive для шахмат раз в секунду?

unix0id
17.07.2010, 17:45
все просто, человеку нужно знать онлайн соперник или нет. если человек закроет браузер alive перстанут посылаться. и если связь не восстановится в течение 15 сек сервер засчитает победу.

rainbowrussia
17.07.2010, 19:11
Вообще, если по-хорошему, это делается не так, а хотя бы через XMLSocket, который открывает 1 соединение и позволяет длительное время обмениваться данными.

unix0id
18.07.2010, 03:14
Да к этому уже пришли... сейчас переписываем. просто для нормальной работы нужно было написать обработчик сокетов. Его бычно пишут на C . А в Сях я не силен учитывая что еще под nix сервера нужно компилировать...
Скажем так сначала подумали что и LoadVariables хватит .... но на деле оказалось что LoadVariables хватает не более чем 300-400 соединений... так что теперь приходится переходить на сокеты.

rainbowrussia
18.07.2010, 04:18
perl вполне подойдет для написания сервера

unix0id
18.07.2010, 04:30
ну, возможно... А кто ни будь знает, будет ли заметна разница производительности-нагрузки при написании сокетов на перле, по отношению скажем к тем же C'ям?

Котяра
18.07.2010, 12:43
perl я бы не советовал использовать для игрового сервера.
и си тоже.
Конечно всё зависит от программистов.
Но на своём опыте скажу, что если это не будет на 100% гуру - получится лажа.
Лучше яву, тем более, что есть куча готовых серваков. Поищите на форуме - были обсуждения, какой язык выбрать для сервера.

unix0id
19.07.2010, 03:04
send to: Котяра
msg: Ок спасибо, нашел пару дельных обсуждений на эту тему.