“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
가 호출되면 b
및 c
. 때 b
와 c
호출의 지역 변수 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
'Nice programing' 카테고리의 다른 글
순환 참조를 사용하여 JavaScript 객체 문자열 화 (JSON으로 변환) (0) | 2020.11.11 |
---|---|
셸에서 셀러리 주기적 작업을 수동으로 실행하려면 어떻게해야합니까? (0) | 2020.11.11 |
TriviallyCopyable이 아닌 객체에 대해 std :: memcpy의 동작이 정의되지 않은 이유는 무엇입니까? (0) | 2020.11.11 |
PowerShell을 시작하는 방법은 무엇입니까? (0) | 2020.11.11 |
다음 코드에서 sys.sp_addextendedproperty의 사용을 설명 할 수 있습니까? (0) | 2020.11.11 |