Nice programing

“RangeError : 최대 호출 스택 크기를 초과했습니다.”이유는 무엇입니까?

nicepro 2020. 11. 11. 20:38
반응형

“RangeError : 최대 호출 스택 크기를 초과했습니다.”이유는 무엇입니까?


내가 달리면

Array.apply(null, new Array(1000000)).map(Math.random);

Chrome 33에서는

RangeError: Maximum call stack size exceeded

왜?


브라우저는 그렇게 많은 인수를 처리 할 수 ​​없습니다. 예를 들어 다음 스 니펫을 참조하십시오.

alert.apply(window, new Array(1000000000));

이것은 RangeError: Maximum call stack size exceeded당신의 문제와 동일한 결과를 낳습니다.

이를 해결하려면 다음을 수행하십시오.

var arr = [];
for(var i = 0; i < 1000000; i++){
    arr.push(Math.random());
}

여기서는 호출이 Array.apply(null, new Array(1000000))아니라 실패합니다 .map.

모든 함수 인수는 콜 스택 (적어도 각 인수의 포인터)에 맞아야하므로 콜 스택에 대한 인수가 너무 많습니다.

호출 스택 이 무엇인지 이해해야합니다 .

스택 은 푸시 및 팝 메서드 만 지원하는 배열과 같은 LIFO 데이터 구조입니다.

간단한 예를 통해 어떻게 작동하는지 설명하겠습니다.

function a(var1, var2) {
    var3 = 3;
    b(5, 6);
    c(var1, var2);
}
function b(var5, var6) {
    c(7, 8);
}
function c(var7, var8) {
}

here 함수 a가 호출되면 bc. bc호출의 지역 변수 a가 있기 때문에 자바 스크립트의 역할 범위 지정의 액세스 할 수 없습니다, 그러나 호출 스택으로 그들을 밀어 있도록 자바 스크립트 엔진은 지역 변수 및 인수를 기억해야합니다. Narcissus 와 같은 자바 스크립트 언어로 자바 스크립트 엔진을 구현한다고 가정 해 보겠습니다 .

callStack을 배열로 구현합니다.

var callStack = [];

함수가 호출 될 때마다 지역 변수를 스택에 넣습니다.

callStack.push(currentLocalVaraibles);

함수 호출이 완료되면 (에서와 같이를 a호출 b하고 b실행을 마치고로 돌아 가야 함 a) 스택을 팝하여 로컬 변수를 다시 가져옵니다.

currentLocalVaraibles = callStack.pop();

따라서 다시 a호출하고 싶을 c스택에있는 지역 변수를 푸시합니다. 아시다시피 효율적인 컴파일러는 몇 가지 한계를 정의합니다. 여기에 당신이하고있는 경우 Array.apply(null, new Array(1000000)), 당신 currentLocalVariables은이 때문에 객체는 거대 할 것이다 1000000내부 변수를. 이후 .apply주어진 각 배열 요소를 함수에 대한 인수로 전달합니다. 호출 스택에 푸시되면 호출 스택의 메모리 제한을 초과하고 해당 오류가 발생합니다.

무한 recursion ( function a() { a() }) 에서 같은 오류가 너무 많이 발생 하여 항목이 호출 스택으로 푸시되었습니다.

나는 컴파일러 엔지니어가 아니며 이것은 단지 무슨 일이 일어나고 있는지를 단순화 한 표현 일뿐입니다. 이것은 정말로 이것보다 더 복잡합니다. 일반적으로 콜 스택에 푸시 되는 것은 인수, 지역 변수 및 함수 주소를 포함하는 스택 프레임 이라고 합니다.


먼저 Call Stack을 이해해야합니다. 호출 스택을 이해하면 JavaScript 엔진에서 "함수 계층 구조 및 실행 순서"가 어떻게 작동하는지 명확하게 알 수 있습니다.

호출 스택은 주로 함수 호출 (호출)에 사용됩니다. 호출 스택이 단일이기 때문에 함수 실행이 위에서 아래로 한 번에 하나씩 수행됩니다. 이는 호출 스택이 동기적임을 의미합니다. 함수를 입력하면 해당 함수에 대한 항목이 호출 스택으로 푸시되고 함수를 종료하면 동일한 항목이 호출 스택에서 팝됩니다. 따라서 기본적으로 모든 것이 원활하게 실행되면 맨 처음과 끝에서 호출 스택이 비어있는 것으로 표시됩니다.

다음은 호출 스택의 그림입니다. 여기에 이미지 설명 입력

이제 너무 많은 인수를 제공하거나 처리되지 않은 재귀 호출 내부에서 포착 된 경우. 당신은 만날 것입니다

RangeError : 최대 호출 스택 크기를 초과했습니다.

다른 사람들이 설명했듯이 아주 분명합니다. 여기에 이미지 설명 입력 여기에 이미지 설명 입력

도움이 되었기를 바랍니다 !


The answer with for is correct, but if you really want to use functional style avoiding for statement - you can use the following instead of your expression:

Array.from(Array(1000000), () => Math.random());

The Array.from() method creates a new Array instance from an array-like or iterable object. The second argument of this method is a map function to call on every element of the array.

Following the same idea you can rewrite it using ES2015 Spread operator:

[...Array(1000000)].map(() => Math.random())

In both examples you can get an index of the iteration if you need, for example:

[...Array(1000000)].map((_, i) => i + Math.random())

참고URL : https://stackoverflow.com/questions/22123769/rangeerror-maximum-call-stack-size-exceeded-why

반응형