Hướng dẫn how big is the call stack javascript? - ngăn xếp cuộc gọi javascript lớn như thế nào?

Tìm kích thước của bộ nhớ được phân bổ cho ngăn xếp.

Các biến trong JavaScript (và hầu hết các ngôn ngữ lập trình khác) được lưu trữ ở hai nơi: Stack và Heap. Một ngăn xếp thường là một khu vực liên tục của bộ nhớ phân bổ bối cảnh cục bộ cho mỗi hàm thực thi. Heap là một khu vực lớn hơn nhiều lưu trữ mọi thứ được phân bổ động. Sự tách biệt này rất hữu ích để làm cho việc thực hiện an toàn hơn từ tham nhũng (ngăn xếp được bảo vệ nhiều hơn) và nhanh hơn (không cần thu thập rác động của khung ngăn xếp, phân bổ khung hình mới nhanh).

Một ví dụ về ngăn xếp điển hình

1
2
3
function foo() { var a = 1; }
function bar() { var b = 2; foo(); }
bar();

xếp chồng khi thực hiện được tạm dừng bên trong

function foo() { var a = 1; }
function bar() { var b = 2; foo(); }
bar();
3

start of the stack
---------------------------
bar local frame
  * a couple of OS pointers
  * local variable b (2)
  * place for returned value
  * pointer to next frame
---------------------------
foo local frame
  * a couple of OS pointers
  * local variable a (1)
  * place for returned value

Ngay cả khi một hàm tự gọi mình là đệ quy, mỗi khung có bản sao riêng của tất cả các biến cục bộ.

Khi một hàm kết thúc thực thi, khung của nó được xóa khỏi ngăn xếp, giải phóng bộ nhớ được phân bổ bởi tất cả các biến cục bộ. Đây là lý do tại sao ngay cả trong các ngôn ngữ như C hoặc C ++, bạn không bao giờ phải lo lắng về việc giải phóng các biến cục bộ.

Kích thước ngăn xếp

Chúng ta có thể thử tính toán kích thước của ngăn xếp. Nếu một hàm đệ quy phân bổ quá nhiều khung hình trên ngăn xếp, môi trường JavaScript ném một ngoại lệ

function foo() { var a = 1; }
function bar() { var b = 2; foo(); }
bar();
4. Dưới nút 0.11.10 x64 Chương trình đệ quy sau đây có thể báo cáo số lần một hàm nhỏ thực hiện trước khi chết

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var counter = 0;
try {
function foo() {
counter += 1;
foo();
}
foo();
} catch(e) {
console.error(e);
console.log('counter =', counter);
}

[RangeError: Maximum call stack size exceeded]
counter = 20961

Hãy tăng kích thước của mỗi khung bằng cách có một biến cục bộ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var counter = 0;
try {
function foo() {
var local = 1;
counter += 1;
foo();
}
foo();
} catch(e) {
console.error(e);
console.log('counter =', counter);
}

[RangeError: Maximum call stack size exceeded]
counter = 17967

Một số trong JavaScript chiếm 8 byte, điều này cho phép chúng tôi tính toán kích thước ngăn xếp tối đa và kích thước của mỗi khung

N - size of single stack frame
20961 * N = 17967 * (N + 8)
(20961 - 17967) * N = 17967 * 8
2994 * N = 143736
N = 143736 / 2994 = 48 bytes = 6 numbers
Total stack size = 20961 * 48 = 1006128 < 1MB

Không có bất kỳ biến cục bộ nào, mỗi cuộc gọi hàm chiếm 48 byte trong quá trình thực thi và bạn bị giới hạn dưới 1MB cho tất cả các khung chức năng cục bộ.

Chúng tôi có thể xác nhận kích thước ngăn xếp bằng cách thêm biến cục bộ thứ hai

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var counter = 0;
try {
function foo() {
var local = 1;
counter += 1;
foo();
}
foo();
} catch(e) {
console.error(e);
console.log('counter =', counter);
}

[RangeError: Maximum call stack size exceeded]
counter = 17967

Một số trong JavaScript chiếm 8 byte, điều này cho phép chúng tôi tính toán kích thước ngăn xếp tối đa và kích thước của mỗi khung

function foo() { var a = 1; }
function bar() { var b = 2; foo(); }
bar();
0

Không có bất kỳ biến cục bộ nào, mỗi cuộc gọi hàm chiếm 48 byte trong quá trình thực thi và bạn bị giới hạn dưới 1MB cho tất cả các khung chức năng cục bộ.

Chúng tôi có thể xác nhận kích thước ngăn xếp bằng cách thêm biến cục bộ thứ hai

var counter = 0;
try {
function foo() {
var local = 1, local2 = true;
counter += 1;
foo();
}
foo();
} catch(e) {
console.error(e);
console.log('counter =', counter);
}

[RangeError: Maximum call stack size exceeded]
counter = 15721

Sử dụng tổng kích thước ngăn xếp trước đó và chia cho bộ đếm

Mỗi biến Boolean và số mất 8 byte bộ nhớ.Biến Heap

Chỉ các loại nguyên thủy được truyền theo giá trị (số, boolean, tham chiếu đến objec) được lưu trữ trên ngăn xếp. Mọi thứ khác được phân bổ động từ nhóm bộ nhớ được chia sẻ được gọi là Heap. Trong JavaScript, bạn không phải lo lắng về việc giải quyết các vật thể bên trong đống, người thu gom rác giải phóng chúng bất cứ khi nào không ai tham khảo chúng. Tất nhiên, việc tạo ra một số lượng lớn các đối tượng mất phí hiệu suất của nó (ai đó cần giữ tất cả các sổ sách kế toán) cộng với phân mảnh bộ nhớ.

Sâu là ngăn xếp cuộc gọi?

Số lượng các cấp của các hàm gọi được sử dụng để phân biệt giữa các trang web cuộc gọi được gọi là độ sâu của ngăn xếp. Độ sâu ngăn xếp cuộc gọi được sử dụng trong phân tích có thể được thay đổi cho phù hợp với ứng dụng của bạn. Theo mặc định, Freja sử dụng độ sâu ngăn xếp cuộc gọi là 1, nghĩa là chỉ có hàm gọi trong cùng được xem xét trong phân tích. is called the call stack depth. The call stack depth used in the analysis can be varied to suit your application. By default Freja uses a call stack depth of 1, that is, only the innermost calling function is considered in the analysis.

Ngăn xếp cuộc gọi trong JavaScript là gì?

Một ngăn xếp cuộc gọi là một cơ chế cho trình thông dịch (như trình thông dịch JavaScript trong trình duyệt web) để theo dõi vị trí của nó trong một tập lệnh gọi nhiều chức năng - chức năng nào hiện đang được chạy và các hàm nào được gọi từ trong chức năng đó, v.v..a mechanism for an interpreter (like the JavaScript interpreter in a web browser) to keep track of its place in a script that calls multiple functions — what function is currently being run and what functions are called from within that function, etc.

Có bao nhiêu ngăn xếp cuộc gọi?

Thường có chính xác một ngăn xếp cuộc gọi được liên kết với một chương trình đang chạy (hoặc chính xác hơn, với mỗi nhiệm vụ hoặc luồng của một quy trình), mặc dù các ngăn xếp bổ sung có thể được tạo để xử lý tín hiệu hoặc đa nhiệm hợp tác (như với SetContext).usually exactly one call stack associated with a running program (or more accurately, with each task or thread of a process), although additional stacks may be created for signal handling or cooperative multitasking (as with setcontext).

Cuộc gọi là Stack Lifo hay FIFO?

Điều này có nghĩa là nó chỉ có một ngăn xếp cuộc gọi và nó chỉ có thể xử lý một câu tại một thời điểm.Ngăn xếp cuộc gọi tuân theo nguyên tắc LIFO (cuối cùng, ra ngoài), điều đó có nghĩa là nó sẽ luôn xử lý cuộc gọi trên đầu ngăn xếp trước.The call stack follows the LIFO (Last In, First Out) principle, which means it will always process the call on top of the stack first.