утечка памяти при создании DOM
вот уже пару дней бьюсь над кодом...суть такова:
есть таблица сформированная с помощью jquery.Datatables...для получения данных используется serverside(php возвращает json)...после отрисовки самой таблицы необходмо наложить на нее дополнительные DOM элементы(ссылки и прочее), для чего написана небольшая функция fnRend с использованием jquery, кот вызывается один раз после отрисовки всей таблицы...вот в ней то и проблема... если обновлять таблицу без вызова fnRend - все работает быстро и практически без утечек памяти... если использовать fnRend, то при каждом обновлении таблицы происходит небольшая, но существенная утечка - особенно это заметно в IE(6 и 8): за 15 мин с обновлением через каждые 10сек(таблица 10х100 ячеек) память вырастает метров на 70!... уже перечитал несколько статей - оптимизировал насколько мог функцию, но все равно что-то остается в памяти при обновлении(обновляется на страница, а только таблица)... может кто посмотрит проф взглядом и найдет еще недочеты в функции, кот могу приводить к утечке?... function fnRend() { //цикл по каждому row таблицы $(oTable_q.fnGetNodes()).each( function() { //массив изначальных данных в ячейках var aData = []; for (var i = 0, len = $("td", this).length; i < len; i++) { aData.push($("td:eq(" + i + ")", this).html()); } //преобразую данные 1-й ячейки - втсавка 3-х ссылок var td = $("<div></div>"); var td0 = td.clone(); $('td:eq(0)', this).html(td0); td0.append('<a href="#"></a>') .append(' ') .append('<a href="#"></a>') .append(' ') .append('<a href="#"></a>') .find('a:eq(0)') .append(aData[0]) .attr("id", "result") .attr("title", "Результат команды") .end() .find('a:eq(1)') .attr("title", "Результат команды в RAW-формате") .append('<img id="raw" src="./images/pic_agr.gif" border=0>') .end() .find('a:eq(2)') .attr('id', 'repeat') .attr("title", "Повтор команды") .addClass('iframe') .append('<img id="repeat" src="./images/pic_agr.gif" border=0>'); //преобразую данные 7-й ячейки var aData7 = aData[7].match(/^([A-Z]+):::([01])$/); $('td:eq(7)', this).html(aData7[1]); if (aData7[2] == '1') { $('td', this).addClass('qrowdisable'); } //преобразую данные 6-й ячейки - преобразование времени из //unixtime в читабельный вид var times = aData[6].split(':'); var dec = ['00','01','02','03','04','05','06','07','08','09']; var day, month, year, date, hour, min, sec, time; for (i = 0; i < 3; i++) { times[i] = new Date(times[i] * 1000); day = ((day = times[i].getDate()) < 10) ? dec[day] : day; month = ((month = times[i].getMonth() + 1) < 10) ? dec[month] : month; year = times[i].getUTCFullYear().toString().substring(2); date = [day, month, year]; hour = ((hour = times[i].getHours()) < 10) ? dec[hour] : hour; min = ((min = times[i].getMinutes()) < 10) ? dec[min] : min; sec = ((sec = times[i].getSeconds()) < 10) ? dec[sec] : sec; time = [hour, min, sec]; delete times[i]; times[i] = date.join('.') + " " + time.join(':'); } var td6 = td.clone(); $('td:eq(6)', this).html(td6); td6.append('<img src="./images/pic_agr.gif">') .append('<img src="./images/pic_agr.gif">') .append(' ') .append('<img src="./images/pic_agr.gif">') .find('img:eq(0)') .attr('id', 'qtime') .attr("title", times[0]) .after(' ' + times[0] + ' ') .end() .find('img:eq(1)') .attr('id', 'stime') .attr("title", times[1]) .end() .find('img:eq(2)') .attr('id', 'etime') .attr("title", times[2]); times = null; //помечаю нужные ячейки тегом span $('td', this).each( function(i) { if ((i >= 1 && i <=5) || i == 7 || i == 8) { var k = (i == 7 || i == 8) ? i - 1 : i; $(this).wrapInner('<span id="td' + k + '"></span>') .find('span') .css("cursor", "pointer"); } }); aData = null; td = null; }); //onClick на всю таблицу - и выборка действия в зависимости от места евента $('#queue_table').unbind(); $('#queue_table').click(function(e) { var form_params = (window.navigator.userAgent.match(/MSIE/)) ? 'left=200,top=100,height=640,width=900,scrollbars=yes' : ''; var data; if (e.target.nodeName == 'SPAN') { var col = { 0 : 'search_tt', 1 : 'search_rr', 2 : 'search_yy', 3 : 'search_ww', 4 : 'search_oo', 5 : 'search_pp', 6 : 'search_zz', 7 : 'search_ss' }; var oSettings = oTable_q.fnSettings(); var k = $(e.target).attr('id').replace("td", ""); $("input[id=" + col[k]+ "]").val($(e.target).text()); oSettings.aoPreSearchCols[k].sSearch = $(e.target).text(); //обновление самой таблицы oTable_q.fnDraw(false); oSettings = null; col = null; } //открытие нового окна else if ($(e.target).attr('id') == 'result') { data = $(e.target).text(); window.open('/cgi-bin/result.pl?guid=' + data, '', form_params); data = null; } else if ($(e.target).attr('id') == 'raw') { data = e.target.parentNode.parentNode; data = $("a:eq(0)", data).text(); window.open('/cgi-bin/show.pl?guid=' + data, '', form_params); data = null; } }); } |
Я вот, кстати, у знатоков jQuery спросить хотел.
Он где-то у себя хранит элементы, которые уже давно потерты? Просто брал элемент через jQuery, что-то с ним делал, потом этот элемент терся через innerHTML родителя. Обычный document.getElementById('id') - выдавал undefind, а $('#id') показывал и сам элемент и все его атрибуты, присвоенные ранее. |
посмотрел с помощью JavaScript Memory Validator...самыми трубоемкими оказались цилы each...изменил их так:
первый(где формируется массив aData) вообще убрал - ведь пользовался только 3-ми значениями из него...стал брать значения сразу через $("td:eq(_номер_ячейки_)", this).html()... второй заменил на такую конструкцию: var tds = [1, 2, 3, 4, 5, 7, 8]; var tde = $("<span></span>").css("cursor", "pointer"); for (i = 0; i < tds.length; i++) { var k = (tds[i] == 7 || tds[i] == 8) ? tds[i] - 1 : tds[i]; data = $("td:eq(" + tds[i] + ")", this).html(); var tdec = tde.clone(); $("td:eq(" + tds[i] + ")", this).html(tdec.html(data)); tdec.attr('id', 'td' + k); } утечки значительно уменьшились, но все равно есть - за час набежало 250 метров... |
Часовой пояс GMT +3, время: 16:41. |