gpt4 book ai didi

javascript - Chrome : How to solve "Maximum call stack size exceeded" errors on Math. max.apply(数学,数组)

转载 作者:可可西里 更新时间:2023-11-01 02:02:02 27 4
gpt4 key购买 nike

我必须找到非常大的数组的最大值和最小值。为此,我正在使用

Math.max.apply(Math, my_array);
Math.min.apply(Math, my_array);

它在 Firefox 和 IE 上运行良好,但在 Chrome 上我总是得到 Maximum call stack size exceeded 错误...我当前的数组有 221954 个元素,这不是我最大的。

有人知道如何在 Chrome 上解决这个错误吗?如何优化最大值和最小值的搜索?

对于那些不相信的人,请在 Chrome 的控制台中尝试:

var xxx = []
for(var i=0; i<300000; i++){
xxx.push(Math.random());
}
Math.max.apply(Math, xxx);

---> RangeError:超出最大调用堆栈大小

最佳答案

这个问题与 Math.max 和 Math.min 无关。

Function.prototype.apply 只能接收有限长度的数组作为它的第二个参数。

在本地,我使用以下方法在 Chrome 中对其进行了测试:

function limit(l) {
var x = []; x.length = l;
(function (){}).apply(null, x);
}

在本地,limit(l) 在 l = 124980 时崩溃。在 canary 中,这是另一个数字,但也是 ~125k。

这是为什么会发生这种情况的示例解释:https://code.google.com/p/v8/issues/detail?id=2896 (它在其他 JS 引擎中也是可重现的,例如 MDN 提到了这个问题:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply#Using_apply_and_built-in_functions(以“但要小心......”开头),指向 WebKit bugzilla 中的这个问题:https://bugs.webkit.org/show_bug.cgi?id=80797)。据我了解为什么在 V8 中抛出 RangeError:

V8 在汇编中实现了 Function.prototype.apply。在调用函数之前,它应该放置所有函数调用参数,例如thisArg 和第二个 arg 数组的所有成员,一个接一个,在调用 javascript 函数之前压入堆栈。但是堆栈的容量是有限的,如果你达到了限制,你会得到 RangeError。

这是我在 V8 源代码中找到的(IA-32 程序集,builtins-ia32.cc):

void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
static const int kArgumentsOffset = 2 * kPointerSize;
static const int kReceiverOffset = 3 * kPointerSize;
static const int kFunctionOffset = 4 * kPointerSize;
{
FrameScope frame_scope(masm, StackFrame::INTERNAL);

__ push(Operand(ebp, kFunctionOffset)); // push this
__ push(Operand(ebp, kArgumentsOffset)); // push arguments
__ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);

// Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
Label okay;
ExternalReference real_stack_limit =
ExternalReference::address_of_real_stack_limit(masm->isolate());
__ mov(edi, Operand::StaticVariable(real_stack_limit));
// Make ecx the space we have left. The stack might already be overflowed
// here which will cause ecx to become negative.
// !! ADDED COMMENT: IA-32 stack grows downwards, if address to its current top is 0 then it cannot be placed any more elements into. esp is the pointer to stack top.
__ mov(ecx, esp);
// !! ADDED COMMENT: edi holds the "real_stack_limit", which holds the minimum address that stack should not grow beyond. If we subtract edi from ecx (=esp, or, in other words, "how much space is left on the stack"), we may get a negative value, and the comment above says that
__ sub(ecx, edi);
// Make edx the space we need for the array when it is unrolled onto the
// stack.
// !! ADDED COMMENT: eax holds the number of arguments for this apply call, where every member of the 2nd argument array counts as separate argument
__ mov(edx, eax);
// !! ADDED COMMENT: kPointerSizeLog2 - kSmiTagSize is the base-2-logarithm of how much space would 1 argument take. By shl we in fact get 2^(kPointerSizeLog2 - kSmiTagSize) * arguments_count, i.e. how much space do actual arguments occupy
__ shl(edx, kPointerSizeLog2 - kSmiTagSize);
// Check if the arguments will overflow the stack.
// !! ADDED COMMENT: we compare ecx which is how much data we can put onto stack with edx which now means how much data we need to put onto stack
__ cmp(ecx, edx);
__ j(greater, &okay); // Signed comparison.

// Out of stack space.
__ push(Operand(ebp, 4 * kPointerSize)); // push this
__ push(eax);
__ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);

请检查!!添加评论以解释我是如何理解它的。

这是用 JS 编写的 APPLY_OVERFLOW 函数(同样,V8 源代码,runtime.js):

function APPLY_OVERFLOW(length) {
throw %MakeRangeError('stack_overflow', []);
}

编辑:在你的情况下,我会这样:

var max = -Infinity; 
for(var i = 0; i < arr.length; i++ ) if (arr[i] > max) max = arr[i];

关于javascript - Chrome : How to solve "Maximum call stack size exceeded" errors on Math. max.apply(数学,数组),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18308700/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com