Điều chỉnh trình thu gom rác của nodejs

Trước đây, khi bạn đang viết một chương trình, bạn sẽ làm những việc kỳ lạ như malloc hoặc tự do quản lý bộ nhớ chương trình của mình

Trong các ngôn ngữ hiện đại, Garbage Collector (GC) xử lý tất cả những điều này cho bạn. Điều này cũng đúng với NodeJS sử dụng V8 đến GC và thực thi tất cả mã javascript

Hiểu rõ về các cơ chế đằng sau GC có thể giúp bạn tránh được cơn ác mộng của nhà phát triển cuối cùng; . Hơn nữa, giám sát GC có thể giúp bạn tối ưu hóa ứng dụng của mình

Một cơn ác mộng trông như thế nào. Tại sao bạn nên quan tâm đến số liệu GC?

Tôi làm việc tại Voodoo, một công ty của Pháp chuyên sản xuất trò chơi điện tử trên điện thoại di động. Chúng tôi gặp rất nhiều vấn đề về hiệu suất, tính khả dụng và khả năng mở rộng do lưu lượng truy cập quá lớn mà cơ sở hạ tầng của chúng tôi hỗ trợ (hàng tỷ sự kiện/yêu cầu mỗi ngày…… không đùa đâu. ). Trong cài đặt này, mọi khía cạnh của phát triển web đều quan trọng và mọi quyết định đều có thể có tác động lớn đến hoạt động kinh doanh của chúng tôi

Hầu hết thời gian, khi làm việc trên một API hoặc dự án có lưu lượng truy cập thấp, chúng tôi không nhận ra mình có thể thực hiện bao nhiêu điều chỉnh hoặc cải tiến. Mặt khác, khi lưu lượng truy cập tăng lên, tất cả những sơ sót trước đó có thể phải trả giá đắt.

Vào năm 2009, Amazon phát hiện ra rằng cứ 100 mili giây độ trễ khiến họ mất 1% doanh số

Vì vậy, việc hiểu rõ các cơ chế của GC cùng với việc giám sát tốt các chỉ số của nó có thể giúp bạn xây dựng một ứng dụng mạnh mẽ hơn, đặc biệt là với các dự án có lưu lượng truy cập cao

thuật toán GC

Trình thu gom rác không nhất thiết phải dọn dẹp bộ nhớ theo cùng một cách mỗi lần. Với V8 có 2 thuật toán chính. Rác và Đánh dấu/Quét/Thu gọn

nhặt rác

Thuật toán này có thể chạy nhiều lần và dọn dẹp một lượng nhỏ bộ nhớ. Khi theo dõi các chu kỳ GC, có thể bạn sẽ thấy thuật toán nhặt rác chạy nhiều nhất

Thuật toán GC nhỏ. Nó chỉ được sử dụng trong không gian mới

Như thể hiện trong hình trên, một chu kỳ nhặt rác về cơ bản sao chép bộ nhớ trong không gian “đến” vào không gian “từ”, sau đó di chuyển tất cả các đối tượng “còn sống” trở lại không gian “đến”. Nếu một số đối tượng quá cũ, chúng sẽ được chuyển đến “không gian cũ”

Khi thuật toán kết thúc, “to space” chỉ chứa các đối tượng còn sống nên được giữ lại. Loại chu trình GC này có những hạn chế quan trọng vốn có trong thuật toán. di chuyển các đối tượng vào bộ nhớ. Đây là lý do tại sao nó chỉ được sử dụng trên không gian mới để dọn dẹp bộ nhớ thường xuyên (nhưng nhỏ)

Đánh dấu / Quét / Thu gọn

Thuật toán này dựa trên một cách tiếp cận đơn giản. đánh dấu các đối tượng trong bộ nhớ để biết đối tượng nào còn “sống”, sau đó quét bộ nhớ để dọn sạch các đối tượng “chết” (không sử dụng). Và cuối cùng, bộ nhớ nhỏ gọn để tối ưu hóa nó

giai đoạn đánh dấu

Thủ tục đệ quy đánh dấu các đối tượng có thể truy cập

V8 sử dụng hệ thống đánh dấu trắng/xám/đen

Về cơ bản, hệ thống đánh dấu này có thể được tóm tắt như thế này

  • trắng. trạng thái ban đầu, đối tượng này vẫn chưa được phát hiện
  • xám. đối tượng đã được phát hiện
  • đen. đối tượng và tất cả các hàng xóm của nó được phát hiện

Để hiểu rõ hơn về giai đoạn này, thật hữu ích khi xem trí nhớ như một cái cây. Mỗi nút đại diện cho một đối tượng trong bộ nhớ và mỗi nhánh đại diện cho một tham chiếu giữa các đối tượng

Ban đầu, tất cả các nút “gốc” sẽ tự động được gắn cờ màu xám vì GC đã biết về chúng. Trong thế giới NodeJs, một nút gốc thường là đối tượng “toàn cầu” hoặc “quy trình”

Khi GC đã phát hiện ra tất cả các nút, tất cả chúng sẽ được đánh dấu bằng màu đen…… hoặc không. Tất cả các đối tượng “trắng” còn lại sẽ bị xóa trong giai đoạn quét

Ví dụ về trạng thái bộ nhớ ở cuối giai đoạn đánh dấu

giai đoạn quét

Xóa tất cả các đối tượng (màu trắng) không sử dụng

Toàn bộ mục đích của giai đoạn đánh dấu trước đó là đánh dấu các đối tượng mà bộ nhớ của chúng có thể được giải phóng trong giai đoạn này

giai đoạn nhỏ gọn

Di chuyển tất cả các đối tượng được đánh dấu — và do đó còn sống — đến đầu vùng bộ nhớ

Một tối ưu hóa khác của bộ nhớ. GC không chỉ loại bỏ các đối tượng không sử dụng mà còn cố gắng sắp xếp bộ nhớ để cho phép đọc bộ nhớ nhanh hơn

Sau giai đoạn quét, bộ nhớ được giải phóng có thể được phân tách bằng các khối bộ nhớ vẫn đang được sử dụng

Tác động pha nhỏ gọn Có gì mới trong Onirocco?

Dọn dẹp và nén bộ nhớ không phải là những cải tiến và tối ưu duy nhất mà V8 có thể làm cho bạn. Cơ chế ban đầu đằng sau các chu trình GC như sau. chương trình của bạn bị dừng để GC có thể thực hiện công việc của mình. k. hội chứng “dừng thế giới”

Dừng lại thế giới

Vì vậy, đây là cách nhóm V8 xử lý nó

Đầu tiên, giới thiệu “đánh dấu gia tăng”

Giai đoạn “đánh dấu” mất quá nhiều thời gian?

Bộ thu gom rác chia công việc đánh dấu thành các phần nhỏ hơn

Đánh dấu gia tăng

Tất nhiên, tổng thời gian của tất cả các chu trình GC vẫn như cũ, nhưng luồng chính có sẵn thường xuyên hơn để thực thi mã của bạn. Nó mang lại cảm giác tăng tính trôi chảy trong quá trình thực hiện chương trình của bạn

lười quét

Còn giai đoạn càn quét thì sao? . ừ thì cũng thế thôi nhưng gọi là lười quét

Quét các trang trên cơ sở khi cần thiết cho đến khi tất cả các trang đã được quét

Giai đoạn càn quét có thể được thực hiện ngay lập tức… hoặc có thể bị trì hoãn. Nếu dung lượng bộ nhớ trống đủ để thực thi mã của bạn, tại sao phải thực hiện giai đoạn quét toàn bộ ngay lập tức?

Nó cũng có thể được thực hiện song song. Hãy xem làm thế nào

đồng thời

Các phiên bản mới nhất của V8 có thể thực hiện các chu kỳ GC trên nhiều luồng khác nhau. Bạn có thể hưởng lợi từ cơ chế phân tách nhưng với cách tiếp cận song song, giảm thời gian GC toàn cầu

cách tiếp cận đồng thời

Nhưng bạn vẫn thấy một loại nguyên tắc “dừng thế giới” ở đây. Có cách nào để thoát khỏi nó? . Và nó được gọi là "song song"

Song song, tương đông

Khi có thể, V8 có thể thực hiện các thao tác GC song song với mã của bạn

cách tiếp cận song song

V8 có thể làm gì? . )

Trên thực tế, V8 chọn cách tốt nhất để quản lý bộ nhớ của bạn và thực hiện các thao tác GC. Nó có thể áp dụng tất cả các cơ chế trước đó cùng nhau, như hình ảnh bên dưới tổng hợp

Trường hợp thực tế Làm cách nào để giám sát bộ nhớ và GC?

mô-đun V8

Mô-đun v8 hiển thị các API dành riêng cho phiên bản V8 được tích hợp trong Nút. js nhị phân

Có 2 phương pháp quan trọng trong mô-đun này

  • v8. getHeapStatistic(). Tổng quan về bộ nhớ chung
  • v8. getHeapSpaceStatistic(). bộ nhớ chia theo không gian (mới, cũ, …)

đầu ra cơ bản

mô-đun gc-stats

Hiển thị số liệu thống kê về V8 GC sau khi nó đã được thực thi

Trước hết, mô-đun này không phải là mô-đun tích hợp trong nodejs. Vì vậy, bạn cần phải cài đặt nó

npm install gc-stats

Mô-đun này cho phép bạn nghe “số liệu thống kê” về sự kiện đặc biệt để truy xuất dữ liệu chu kỳ GC

triển khai và đầu ra gc-stats

Tùy chọn V8

V8 có thể in một số thông tin có giá trị về trạng thái của nó và đặc biệt là về cách hoạt động của bộ thu gom rác. Để hiển thị dữ liệu bổ sung này, bạn phải chuyển sang các đối số V8 (so với NodeJs) trước khi bắt đầu ứng dụng của mình

node --trace_gc app.js

Một trong những tùy chọn thú vị nhất để lấy một số dữ liệu GC là --trace_gc. Một đầu ra điển hình sẽ trông như thế này

— đầu ra dấu vết_gc

Cuối cùng, bạn có thể tìm thấy danh sách đầy đủ các tùy chọn V8 tại đây

https://gist.github.com/listochkin/10973974

APM

Cuối cùng nhưng không kém phần quan trọng. đừng bao giờ quên sử dụng apm (Quản lý hiệu suất ứng dụng) để theo dõi việc sử dụng bộ nhớ của bạn trong thời gian thực

Một số trong số chúng cũng có thể hiển thị một vài số liệu về trình thu gom rác, xem hình ảnh bên dưới

Thật không may, trình độ nghệ thuật hiện tại cho thế giới giám sát không thực sự cập nhật với trình thu gom rác NodeJs. Thật vậy, sau khi thử nghiệm rất nhiều công cụ apm, tôi thấy rằng hầu hết chúng không hiển thị tất cả dữ liệu có sẵn và đa số thậm chí không có tính năng này

Phần kết luận

Hiểu về bộ thu gom rác và tại sao vai trò của nó là trung tâm trong quản lý bộ nhớ chương trình của bạn là rất quan trọng nếu bạn muốn nắm vững những gì NodeJ và V8 có thể làm cho bạn. Theo dõi và gỡ lỗi các chu kỳ của GC và trạng thái bộ nhớ có thể giúp bạn tìm ra một số tắc nghẽn về hiệu suất và ngăn ngừa sự cố máy chủ

Bạn cũng nên theo dõi và thiết lập một số cảnh báo tự động trên các chỉ số của GC, chẳng hạn như thời lượng trung bình của chu kỳ GC (không được vượt quá vài mili giây) hoặc tần suất tạm dừng của GC

Bạn có thể tìm thấy bài nói gốc của tôi ở đây. https. // tài liệu. Google. com/presentation/d/17PXOZXBgdJHqBZlbULHg70_hVFLrNx9T34rB9bLDn2M/edit#slide=id. g3ffed3592f_0_0