简单代码中的Javascript内存泄漏

时间:2011-07-01 13:38:17

标签: javascript memory-leaks

我的javascript代码中存在某种内存问题。我一直在网上搜索javascript中的内存泄漏模式,但是这些模式似乎都不适用于我的代码。它是非常简单的代码,没有闭包,我甚至没有内部函数,我的所有变量只包含简单的值,如DOM对象或布尔值,我甚至没有在变量中定义属性。但不知何故,我设法泄漏了大量的内存,Firefox(3.6.11)冻结了,而且IE告诉我第73行我的内存耗尽,我已经标记了这一行。 DOM树中引用的函数是toggle,replyForm和replyExpand。

<script type="text/javascript">
function toggle(expandable){
    if(expandable.parentNode.getElementsByTagName("ul")[0].className=="hide"){
        expandable.parentNode.getElementsByTagName("ul")[0].className="show";
        expandable.innerHTML="▼";
    }
    else{
        expandable.parentNode.getElementsByTagName("ul")[0].className="hide";
        expandable.innerHTML="►";
    }
}

var previousSpan;

function replyForm(span,postId,op,commentID){
    if(removeForm(span))
        return;
    previousSpan=span;

    if(span.nextSibling!=null){
        span.parentNode.insertBefore(form(span,postId,op,commentID),span.nextSibling);
    }
    else{
        span.parentNode.appendChild(form(span,postId,op,commentID));
    }
}

function removeForm(span){
    if(previousSpan==null)
        return false;  <-- Out of memory here according to IE
    if(previousSpan.parentNode.getElementsByTagName("form").length!=0)
previousSpan.parentNode.removeChild(span.parentNode.getElementsByTagName("form")[0]);
    var result=(span==previousSpan);
    if(result)
        collapse(previousSpan);
previousSpan=null;
return result;
}

function form(span,postId,op,commentID){
var result=
"<form id=\"commentform\" method=\"post\" action=\"http://innategamer.300mb.us/wp-comments-post.php\">\n"+
"<p>Replying to "+op+":</p>\n"+
"<p><label for=\"author\">Name *</label><input id=\"author\" type=\"text\" aria-required=\"true\" size=\"30\" value=\"\" name=\"author\"></p>\n"+
"<p>Email *<input id=\"email\" type=\"text\" aria-required=\"true\" size=\"30\" value=\"\" name=\"email\"></p>\n"+
"<p>Website<input id=\"url\" type=\"text\" size=\"30\" value=\"\" name=\"url\"></p>\n"+
"<textarea id=\"comment\" aria-required=\"true\" rows=\"8\" cols=\"45\" name=\"comment\"></textarea>\n"+
"<input id=\"submit\" type=\"submit\" value=\"Post Comment\" name=\"submit\">\n"+
"<input id=\"comment_post_ID\" type=\"hidden\" value=\""+postId+"\" name=\"comment_post_ID\">\n"+
"<input id=\"comment_parent\" type=\"hidden\" value=\""+commentID+"\" name=\"comment_parent\">\n"+
"</form>";
    var div=document.createElement('div');
    div.innerHTML=result;
    return div.firstChild;
}

function replyExpand(span){
    if(span.innerHTML.indexOf("▼")!=-1)
        collapse(span);
    else
        expand(span);
}

function collapse(span){
    if(previousSpan==span)
        removeForm(span);
    span.innerHTML=span.innerHTML.replace("▼","►");
    while(span.nextSibling!=null){
        span=span.nextSibling;
        if(span.className=="comment-content show");
            span.className="comment-content hide";
    }
}

function expand(span){
    span.innerHTML=span.innerHTML.replace("►","▼");
    while(span.nextSibling!=null){
        span=span.nextSibling;
        if(span.className=="comment-content hide");
            span.className="comment-content show";
    }
}


</script>

3 个答案:

答案 0 :(得分:1)

看起来你在那里有一个无限循环。

removeForm来电collapse

collapse来电removeForm

答案 1 :(得分:0)

我不会花时间用细齿梳子来解决这个问题。但我确实看到removeForm来电collapse,有时会调用removeForm。我怀疑的第一件事是这两个函数以某种方式以无限递归模式相互调用。

请尝试在其中一个功能的开头添加断点。

在调试器中,每次遇到此断点时都要检查调用堆栈的大小。如果调用堆栈扩展直到程序内存不足,那么恭喜你,你刚刚在StackOverflow上发布了一个真正的Stack Overflow!

答案 2 :(得分:0)

我认为它与这两个函数相互调用的事实有关,而且据我所知,if语句一旦为真,将永远是真的。

function removeForm(span) {
    if (previousSpan == null) return false; < --Out of memory here according to IE
    if (previousSpan.parentNode.getElementsByTagName("form").length != 0)
        previousSpan.parentNode.removeChild(span.parentNode.getElementsByTagName("form")[0]);
    var result = (span == previousSpan);
    if (result) collapse(previousSpan); // <---------------
    previousSpan = null;  //                               |
    return result;        //                               |
}                         //                               |
                          //                               |
function collapse(span) { //                               |
    if (previousSpan == span) removeForm(span); // <--------
    span.innerHTML = span.innerHTML.replace("▼", "►");
    while (span.nextSibling != null) {
        span = span.nextSibling;
        if (span.className == "comment-content show");
        span.className = "comment-content hide";
    }
}

有效:

var previousSpan;

function removeForm( span ) {
    // ...
    if( span == previousSpan ) collapse(previousSpan);
    // ...
}

function collapse( span ) {  // <---here span is previousSpan,
       // <-- always true because you're doing if(previousSpan == previousSpan)
    if (previousSpan == span) removeForm(span);   
    // ...
}

// This makes subsequent comparisons in "removeForm()" always true as well,
//    because now it is guaranteed that "span" is the same as "previousSpan"

因此,在span == previousSpan removeForm() previousSpan之后,您就会将collapse()传递给collapse()previousSpan做的第一件事是检查它收到的是否等于{{1}},它始终是,因为那是首先发送它的测试。