2012-06-25 39 views
28

Tôi đang cố gắng xây dựng một trang web mà tôi cần xẻng khoảng 100MB dữ liệu bằng JavaScript. Với các trình duyệt khác nhau, tôi chạy vào "kích thước ngăn xếp cuộc gọi tối đa đã vượt quá" lỗi với số lượng dữ liệu khác nhau.Stack so với Heap trong Javascript? (Đã vượt quá kích thước ngăn xếp cuộc gọi tối đa)

Tôi có thể khắc phục sự cố này bằng cách xem mã của mình và cố gắng di chuyển các biến cục bộ bên trong các hàm vào phạm vi toàn cầu hơn để cố gắng phân bổ chúng trên heap thay vì ngăn xếp không? Hay những khái niệm này không tồn tại trong JavaScript? (Theo như tôi biết, tôi không có bất kỳ vòng lặp đệ quy lớn nào trong dữ liệu của mình, vì vậy nó thực sự là một vài chuỗi số/chuỗi số lớn dường như gây ra lỗi)

Nếu điều này là không thể , có cách nào để yêu cầu trình duyệt dành nhiều bộ nhớ hơn không?

+3

+1 cho bài đăng thú vị – pixelbobby

+4

Bạn chưa hiểu những gì bạn đang nhìn thấy . Điều gì đã xảy ra là bạn có một hàm đệ quy, tức là một hàm gọi chính nó (hoặc gọi một hàm khác gọi hàm đầu tiên) có thể do tai nạn. – Ben

+0

(liên quan) http://stackoverflow.com/questions/6602864/stack-and-heap-in-v8-javascript –

Trả lời

16

Không có sự tách biệt bộ nhớ thành chồng/đống trong Javascript. Những gì bạn nhìn thấy có thể là một trong những điều sau đây:

  1. Đợt truy cập chạy quá sâu. Trong trường hợp đó, bạn sẽ cần phải xem lại thuật toán của mình để làm cho thuật toán lặp lại nhiều hơn và sử dụng ít đệ quy hơn, do đó bạn không nhấn ngăn xếp cuộc gọi giới hạn áp đặt bởi trình duyệt.
  2. Nếu thuật toán của bạn không có đệ quy sâu, điều này có thể vẫn chỉ là một cuộc gọi đủ sâu, xem xét mã của bạn được tạo.
  3. Cuối cùng, một số công cụ có thể phân bổ các đối số chức năng và các biến được đặt tên theo phạm vi trên một số loại ngăn xếp nội bộ để tra cứu nhanh. Nếu bạn (hoặc mã được tạo tự động) xảy ra theo nghĩa đen sử dụng hàng nghìn biến cục bộ hoặc đối số trong hàm, điều này có thể làm tràn các giới hạn cụ thể của động cơ.
+0

Tôi chắc chắn rằng đó không phải là vấn đề đệ quy (xem phần chỉnh sửa câu hỏi gốc). –

+0

Bất kể mảng lớn là bao nhiêu, giá trị trong hàm gọi chỉ là con trỏ tới mảng này. Trừ khi hàm của bạn theo nghĩa đen chấp nhận hàng trăm đối số, điều này vẫn không liên quan gì đến bộ nhớ, vì nội dung của mảng sẽ không chuyển sang loại bộ nhớ cụ thể nào khác chỉ vì bạn đã tham chiếu nó trong cuộc gọi. –

+0

Bạn đã chính xác, ít nhất một phần. Chức năng của tôi thực sự chấp nhận hàng trăm đối số (thực sự là hàng triệu). Để biết chi tiết, xem bên dưới. Nhưng điều này có nghĩa là có sự tách biệt bộ nhớ thành đống/đống cho các đối số được chuyển vào một cuộc gọi hàm, ít nhất là đối với Safari và Chrome. –

27

OK, đã tìm ra sự cố. Thực sự không có đệ quy nào trong mã của tôi. Nó thực sự có thể gọi các hàm JavaScript với hàng trăm đối số nếu chúng là các hàm "varargs" như ví dụ <array>.splice(...), là kẻ phạm tội của tôi.

Ngoài: GWT triển khai chức năng Java System.arraycopy(...) sử dụng chức năng ghép nối JavaScript theo cách thông minh hơn hoặc ít hơn.

mối nối chấp nhận số lượng phần tử đầu vào tùy ý để chèn vào mảng đích. Nó có thể vượt qua những yếu tố đầu vào từ mảng khác bằng cách sử dụng các cấu trúc sau:

var arguments = [index, howmany].concat(elements); 
Arrays.prototype.splice.apply(targetarray, arguments); 

này tương đương với cách gọi:

targetarray.splice(index, howmany, elements[0], elements[1], elements[2], ...); 

Nếu yếu tố được lớn (xem dưới đây để biết những gì "lớn "có nghĩa là cho các trình duyệt khác nhau), bạn có thể nhận được lỗi" Kích thước ngăn xếp cuộc gọi tối đa đã vượt quá "mà không cần đệ quy vì nội dung của nó sẽ được tải lên ngăn xếp cho cuộc gọi hàm.

Dưới đây là một kịch bản ngắn đó chứng tỏ vấn đề này:

var elements = new Array(); 
for (i=0; i<126000; i++) elements[i] = 1; 
try { 
    var arguments = [0, 0].concat(elements); 
    Array.prototype.splice.apply(elements, arguments); 
    alert("OK"); 
} catch (err) { 
    alert(err.message); 
} 

Sử dụng kịch bản này, "ông lớn" có nghĩa như sau:

  • Chrome 19: yếu tố chứa ~ 125.000 số
  • Safari 5.1 (trên Windows): các phần tử chứa ~ 65.000 số
  • Firefox 12: các thành phần chứa ~ 500.000 số
  • Opera 11.61: các phần tử chứa ~ 1.000.000 số

Và người chiến thắng là: Internet Explorer 8 để thay đổi! Nó có thể sử dụng hết bộ nhớ hệ thống, trước khi cuộc gọi chức năng này thất bại.

Một mặt lưu ý: Firefox và Opera thực sự ném một (hữu dụng hơn) thông báo lỗi khác nhau: Function.prototype.apply: argArray quá lớn

+3

Ow, tôi biết điều này là có thể, nhưng hy vọng không ai có thể thử điều đó. –

+1

Điều thú vị là: Google thực sự đã chuẩn hóa phương pháp này trong GWT ... :) Đây có lẽ là cách nhanh nhất để triển khai System.arraycopy của Java trong JavaScript, nhưng nó bị phá vỡ đối với mảng lớn ... và, cậu bé, là lỗi này một sự đau đầu để tìm ... –

+0

Lưu ý: nó đã được sửa cho GWT 2.7: https://gwt.googlesource.com/gwt/+log/master/user/super/com/google/gwt/emul/java/ lang/System.java –

Các vấn đề liên quan