2012-01-11 28 views
14

Khi cố gắng gỡ lỗi rò rỉ bộ nhớ trong NodeJS, tôi thấy khá khó khăn (do thiếu công cụ định hình mà tôi biết).ví dụ về đóng cửa trong node.js có thể gây rò rỉ bộ nhớ

Tôi nghĩ tôi muốn quay lại vấn đề cơ bản và đảm bảo rằng tôi hiểu cách rò rỉ bộ nhớ sẽ được tạo cụ thể trong NodeJS. Tôi đang bối rối về các loại đóng cửa có thể gây ra rò rỉ bộ nhớ và không chắc chắn về những gì các bộ thu rác cần để giải phóng bộ nhớ đó.

Bạn có thể cho tôi một số ví dụ về các mẫu cơ bản có thể gây rò rỉ bộ nhớ trong Node.js không?

Trả lời

17

Không phải là "rò rỉ" chính xác, nhưng điều này có thể là một lỗ hổng phổ biến.

var fn = (function() { 
    var a = "super long string ..."; 
    var b = "useless value"; 
    var c = "Hello, World!"; 

    return function() { 
    return c; 
    }; 
})(); 

này trả về một chức năng tham chiếu đến một phạm vi, và mỗi var địa phương duy nhất trong phạm vi đó sẽ được lưu giữ, mặc dù chỉ là một trong những giá trị đó là cần thiết. Điều này dẫn đến việc sử dụng bộ nhớ nhiều hơn mức bạn cần, đặc biệt nếu hàm của bạn sử dụng một biến nhỏ, nhưng có những giá trị lớn trong phạm vi đó mà bạn không cần phải tham khảo.


Cách khắc phục?

Tùy chọn đơn giản là loại bỏ các biến mà bạn không quan tâm ở phần cuối của hàm. Các biến vẫn nằm trong phạm vi, nhưng dữ liệu của chúng sẽ được giải phóng.

var fn = (function() { 
    var a = "super long string ..."; 
    var b = "useless value"; 
    var c = "Hello, World!"; 

    // do stuff with a and b 

    a = b = null; 

    return function() { 
    return c; 
    }; 
})(); 

Hoặc bạn có thể phá vỡ bất kỳ thứ gì sử dụng temp nhiệt độ vào chức năng riêng của nó để phạm vi của chúng có thể được giải phóng. Đây là một giải pháp tốt hơn cho một dự án lớn hơn.

var doSetup = function() { 
    var a = "super long string ..."; 
    var b = "useless value"; 
    // do stuff with a and b 
}; 

var fn = (function() { 
    doSetup(); 

    var c = "Hello, World!"; 

    return function() { 
    return c; 
    }; 
})(); 
+0

điều gì sẽ xảy ra nếu nó không trả về c nhưng đã tham chiếu đến nó như sau: 'var fn = (function() { var a =" siêu dài chuỗi ... "; var b =" useless value " ; var c = "Xin chào, Thế giới!"; chức năng() { c = "cái gì khác"; }; })(); ' – crickeys

+0

Vấn đề là nếu chức năng vẫn được tham chiếu, phạm vi đóng được tạo ra sẽ được giữ trong bộ nhớ. Chức năng đó thực sự không ảnh hưởng gì đến thực tế đó. –

+0

Vì vậy, làm cách nào bạn sửa mã gốc mà bạn đã đăng để đảm bảo mã không bị rò rỉ nữa? – crickeys

-1

Từ: http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml?showone=Closures#Closures

Một điều cần lưu ý, tuy nhiên, đó là một đóng giữ một con trỏ đến phạm vi bao quanh nó. Kết quả là, việc gắn một đóng vào một phần tử DOM có thể tạo ra một tham chiếu vòng tròn và do đó, một sự rò rỉ bộ nhớ. Ví dụ: trong mã sau:

function foo(element, a, b) { 
    element.onclick = function() { /* uses a and b */ }; 
} 

đóng chức năng giữ tham chiếu đến phần tử, a và b ngay cả khi nó không bao giờ sử dụng phần tử. Vì yếu tố cũng giữ một tham chiếu đến việc đóng cửa, chúng tôi có một chu kỳ mà sẽ không được làm sạch bằng cách thu gom rác thải. Trong những tình huống này, các mã có thể được cấu trúc như sau:

function foo(element, a, b) { 
    element.onclick = bar(a, b); 
} 

function bar(a, b) { 
    return function() { /* uses a and b */ } 
} 
+1

có phần hữu ích, nhưng tôi không quan tâm đến bất kỳ điều gì với các phần tử DOM vì đây là Node.JS – crickeys

0
  1. Bạn có thể sử dụng nút-thanh tra các ứng dụng nút debug với các công cụ dev Chrome.

  2. Câu trả lời được chấp nhận về biến đóng không sử dụng là sai vì trong các công cụ JS hiện đại, chỉ những biến thực sự được tham chiếu trong hàm bên trong mới được bao gồm trong phạm vi đóng. Phần còn lại được thu gom rác tự động. Nói cách khác, điều kiện lý thuyết này sẽ không bao giờ thực sự xảy ra trong Node. Đối với một ví dụ thực tế (và khá phổ biến) sử dụng Express, bạn có thể tạo phần mềm trung gian để tải một tệp vào bộ nhớ cho mỗi yêu cầu và sau đó ném một ngoại lệ chưa được xử lý trong cùng yêu cầu đó, bắt ngoại lệ được ném, và sau đó không thành công thoát khỏi quá trình.

Trường hợp ngoại lệ được ném sẽ khiến tài nguyên yêu cầu được tải thay vì được dọn sạch vào cuối chu kỳ yêu cầu/phản hồi.

Không thoát khỏi quá trình khi ngoại lệ xảy ra có nghĩa là thay vì tắt và khởi động lại bằng một cái gì đó như PM2 hoặc Vô hạn, Node sẽ bỏ qua lỗi và tiếp tục yêu cầu mới như thể không có gì xảy ra. Vì các tài nguyên không được dọn dẹp, quá trình này sẽ tiêu tốn nhiều bộ nhớ hơn theo thời gian cho đến khi nó giảm hiệu năng của máy và cuối cùng hết dung lượng để cấp phát các tài nguyên mới.

Điều đó rõ ràng sẽ có tác động tiêu cực đến trải nghiệm người dùng.

Xem thêm Why Would an Exception Cause Resource Leaks in Node.js.

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