Theo tài liệu node.js, một nút có giới hạn 512meg trên phiên bản 32 bit và giới hạn 1,4gig trên phiên bản 64bit. Các giới hạn tương tự cho Chrome AFAICT. (+/- 25%)Tại sao v8 hết bộ nhớ trong tình huống này?
Vì vậy, tại sao mã này hết bộ nhớ khi nó không bao giờ sử dụng nhiều hơn ~ 424meg bộ nhớ?
Đây là mã (Mã này là vô nghĩa. Câu hỏi này không phải về mã đang làm gì đó là lý do mã bị lỗi).
var lookup = 'superCaliFragilisticExpialidosiousThispartdoesnotrealllymattersd';
function encode (num) {
return lookup[num];
}
function makeString(uint8) {
var output = '';
for (var i = 0, length = uint8.length; i < length; i += 3) {
var temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]);
output += encode(temp >> 18 & 0x3F) + encode(temp >> 12 & 0x3F) + encode(temp >> 6 & 0x3F) + encode(temp & 0x3F);
}
return output;
}
function test() {
var big = new Uint8Array(64 * 1024 * 1024 + 2); // multiple of 3
var str = makeString(big);
console.log("big:", big.length);
console.log("str:", str.length);
}
test();
Như bạn có thể thấy makeString
tạo chuỗi bằng cách thêm 4 ký tự cùng một lúc. Trong trường hợp này nó sẽ xây dựng một chuỗi dài 89478988 (180meg) lớn. Kể từ khi output
được thêm vào, các ký tự thời gian cuối cùng được nối thêm sẽ có 2 chuỗi trong bộ nhớ. Cái cũ với 89478984 ký tự và cái cuối cùng với 89478988. GC nên thu thập bất kỳ bộ nhớ nào khác được sử dụng.
Vì vậy, 64meg (mảng ban đầu) + 180meg * 2 = 424meg. Cũng theo giới hạn v8.
Nhưng, nếu bạn chạy mẫu nó sẽ thất bại với ra khỏi bộ nhớ
<--- Last few GCs --->
3992 ms: Scavenge 1397.9 (1458.1) -> 1397.9 (1458.1) MB, 0.2/0 ms (+ 1.5 ms in 1 steps since last GC) [allocation failure] [incremental marking delaying mark-sweep].
4450 ms: Mark-sweep 1397.9 (1458.1) -> 1397.9 (1458.1) MB, 458.0/0 ms (+ 2.9 ms in 2 steps since start of marking, biggest step 1.5 ms) [last resort gc].
4909 ms: Mark-sweep 1397.9 (1458.1) -> 1397.9 (1458.1) MB, 458.7/0 ms [last resort gc].
$ node foo.js
<--- JS stacktrace --->
==== JS stack trace =========================================
Security context: 0x3a8521e3ac1 <JS Object>
2: makeString(aka makeString) [/Users/gregg/src/foo.js:~6] [pc=0x1f83baf53a3b] (this=0x3a852104189 <undefined>,uint8=0x2ce813b51709 <an Uint8Array with map 0x32f492c0a039>)
3: test(aka test) [/Users/gregg/src/foo.js:19] [pc=0x1f83baf4df7a] (this=0x3a852104189 <undefined>)
4: /* anonymous */ [/Users/gregg/src/foo.js:24] [pc=0x1f83baf4d9e5] (this=0x2ce813b...
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory
Abort trap: 6
đã thử cả hai nút 4.2.4 và 5.6.0
Vì vậy, câu hỏi là tại sao nó lại chạy ra bộ nhớ?
Một số điều tôi đã thử.
tôi đã cố gắng gia nhập khối
Thay vì gắn liền với các
output
vô thời hạn Tôi đã cố gắng kiểm tra nếu nó lớn hơn một số kích thước (như 8k). Nếu vậy tôi đặt nó vào một mảng và đặt lại đầu ra cho chuỗi rỗng.Bằng cách thực hiện việc này
output
không bao giờ lớn hơn 8k. Mảng giữ 180meg + sổ sách kế toán. Vì vậy, 180meg + 8k nhỏ hơn 180meg + 180meg. Nó vẫn hết bộ nhớ. Bây giờ, vào cuối quá trình đó, tôi tham gia vào mảng tại thời điểm đó nó sẽ thực sự sử dụng nhiều bộ nhớ hơn (180meg + 180meg + bookeeping). Tuy nhiên, v8 bị treo trước khi nó được chuyển đến dòng đó.Tôi đã cố gắng thay đổi mã hóa để chỉ
function encode(num) { return 'X'; }
Trong trường hợp này nó thực sự chạy đến khi kết thúc !! Vì vậy, tôi nghĩ, "A-ha! vấn đề này phải được một cái gì đó liên quan đến
lookup[num]
tạo một chuỗi mới mỗi gọi? Vì vậy, tôi đã cố gắng ...Changed
lookup
đến mảng các chuỗivar lookup = Array.prototype.map.call( 'superCaliFragilisticExpialidosiousThispartdoesnotrealllymattersd', function(c) { return c; });
Vẫn hết bộ nhớ
Điều này có vẻ như lỗi trong v8?Nó không thể GC không sử dụng chuỗi một cách kỳ lạ vì mã này mặc dù # 2 vs # 3 là lạ vì chúng có vẻ tương đương về mặt sử dụng bộ nhớ.
Tại sao v8 hết bộ nhớ trong các trường hợp này? (và có cách giải quyết khác)
Hầu hết những người thu gom rác sẽ * đóng băng thế giới * khi chúng hết bộ nhớ và đòi lại bất kỳ bộ nhớ nào có thể đòi lại. Xem câu trả lời được chấp nhận vì sao nó hết bộ nhớ nếu bạn tò mò – gman