jQuery / Sizzle checkContext内存泄漏 [英] jQuery/Sizzle checkContext memory leak
问题描述
在DevTools中使用Profiles调试我的应用程序时,我发现已分离的DOM树已累积。这些分离的节点具有主要由 checkContext
函数组成的保留树(来自,修复它,运行所有Sizzle测试,并做了一个拉请求。
如果您要修补现有的jQuery或Sizzle副本:
-
打开您的jQuery或Sizzle文件
-
搜索
matcherFromTokens
function -
查找此代码(靠近顶部):
matchers = [function(elem,context,xml){
return(!leadingRelative&&(xml || context!==mostContext))|| (
(checkContext = context).nodeType?
matchContext(elem,context,xml):
matchAnyContext(elem,context,xml));
}];
-
将
返回
code> var rv = ,并添加checkContext = undefined;
然后return rv;
在匿名函数的末尾,例如:matchers = [function(elem,context,xml){
var ret =(!leadingRelative&&((xml || context!==mostContext))|| (
(checkContext = context).nodeType?
matchContext(elem,context,xml):
matchAnyContext(elem,context,xml));
//释放上下文节点(问题#299)
checkContext = null;
return ret;
}];
注意该代码将 null
分配给 checkContext
,因为这显然是他们的风格。如果是我,我会分配 undefined
。
如果提出修复有任何问题在拉动请求/合并过程中,我将更新答案。
最好不要让Sizzle缓存选择器,因为jQuery使用编译的选择器事件与事件委托,而且您每次发生相关事件时,都不需要重新分析并重建匹配器函数,因此可以确定元素是否匹配。
不幸的是,这不是jQuery对编译选择器中元素的唯一位置。它所做的每个地方可能是一个可以使用修复的bug。我只有时间跟踪另一个,我也已经报告和修复(等待提出请求登陆):
如果您搜索潜在复杂的伪造你会发现这个:不是
伪选择器:
pseudos:{
//潜在的复杂伪元素
not:markFunction(function(selector){
//修剪传递给编译器
//以避免将
//空格作为组合器处理
var input = [],
results = [],
matcher = compile(selector)替换(rtrim,$ 1));
返回匹配器[expando]?
markFunction(function(seed,matches,context,xml){
var elem,
unmatched = matcher(seed,null,xml,[]),
i = seed.length;
//匹配不匹配的元素matcher
while(i--){
if((elem = unmatched [i])){
seed [i] =!(matches [i] = elem);
}
}
}):
函数(elem,context,xml){
input [0] = elem;
匹配(input,null,xml,results);
return!results.pop();
};
}),
问题出在 :
在条件运算符中:
函数(elem,context,xml){
输入[0] = elem;
匹配(input,null,xml,results);
return!results.pop();
};
请注意,它不会清除 input [0]
。这是修复:
function(elem,context,xml){
input [0] = elem;
匹配(input,null,xml,results);
//不要保留元素(问题#299)
input [0] = null;
return!results.pop();
};
现在我有时间跟踪。
While debugging my app with 'Profiles' in DevTools I found "Detached DOM tree's" accumulating. These detached nodes have retaining tree consisting mostly of checkContext
functions (coming from sizzle inside jQuery - v1.10.1).
I'm not sure how to proceed with this. What does this result mean?
This is actually a bug, there's no reason that Sizzle needs to hang onto the context node, it's only doing it because it's not cleaning up after setting a temporary variable. I filed an issue for it, fixed it, ran all the Sizzle tests, and did a pull request.
If you want to patch your existing copy of jQuery or Sizzle:
Open your jQuery or Sizzle file
Search for the
matcherFromTokens
functionFind this code within it (near the top):
matchers = [ function( elem, context, xml ) { return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( (checkContext = context).nodeType ? matchContext( elem, context, xml ) : matchAnyContext( elem, context, xml ) ); } ];
Change the
return
tovar rv =
, and addcheckContext = undefined;
and thenreturn rv;
at the end of the anonymous function, e.g.:matchers = [ function( elem, context, xml ) { var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( (checkContext = context).nodeType ? matchContext( elem, context, xml ) : matchAnyContext( elem, context, xml ) ); // Release the context node (issue #299) checkContext = null; return ret; } ];
Note: That code assigns null
to checkContext
because apparently that's their style. If it were me, I'd've assigned undefined
instead.
If there's any issue with the fix raised during the pull request / merge process, I'll update the answer.
It's better to keep letting Sizzle cache selectors, because jQuery uses the compiled selector stuff with event delegation, and you don't really want it to have to reparse and rebuild the matcher functions each time a relevant event occurs so it can figure out whether elements match it.
This isn't the only place jQuery holds onto elements in compiled selectors, unfortunately. Each place it does is probably a bug that could use fixing. I've only had the time to track down one other, which I've also reported and fixed (pending the pull request being landed):
If you search for "Potentially complex pseudos" you'll find this for the :not
pseudo-selector:
pseudos: {
// Potentially complex pseudos
"not": markFunction(function( selector ) {
// Trim the selector passed to compile
// to avoid treating leading and trailing
// spaces as combinators
var input = [],
results = [],
matcher = compile( selector.replace( rtrim, "$1" ) );
return matcher[ expando ] ?
markFunction(function( seed, matches, context, xml ) {
var elem,
unmatched = matcher( seed, null, xml, [] ),
i = seed.length;
// Match elements unmatched by `matcher`
while ( i-- ) {
if ( (elem = unmatched[i]) ) {
seed[i] = !(matches[i] = elem);
}
}
}) :
function( elem, context, xml ) {
input[0] = elem;
matcher( input, null, xml, results );
return !results.pop();
};
}),
The problem is in the function after the :
in the conditional operator:
function( elem, context, xml ) {
input[0] = elem;
matcher( input, null, xml, results );
return !results.pop();
};
Note that it never clears input[0]
. Here's the fix:
function( elem, context, xml ) {
input[0] = elem;
matcher( input, null, xml, results );
// Don't keep the element (issue #299)
input[0] = null;
return !results.pop();
};
That's all I have the time to track down at present.
这篇关于jQuery / Sizzle checkContext内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!