Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Ruby

Tìm hiểu sâu Garbage Collection của Ruby: Giải thích triển khai MRI

Trong tập trước của Ruby Magic chúng ta nói về tại sao cần Garbage Collection (GC) và cách nó hoạt động nói chung. Bài này sẽ đi sâu vào cách triển khai trong Ruby.

Các triển khai Ruby khác nhau

Có nhiều triển khai Ruby. Ba cái phổ biến: MRI (Matz's Ruby Interpreter), Rubinius và JRuby. Các triển khai khác nhau dùng phương pháp GC khác nhau. Bài này tập trung vào MRI, cái mà hầu hết lập trình viên Ruby dùng.

Heap của Ruby

Máy tính có hai loại bộ nhớ: Stack và Heap. Stack rất nhanh và cục bộ cho ngữ cảnh gọi hàm. Nghĩa là mọi biến khai báo trên stack được giải phóng ngay khi hàm kết thúc. Stack giới hạn kích thước, nên không lưu được đối tượng lớn như dữ liệu ảnh hay file.

Đây không phù hợp để lưu đối tượng Ruby. Các đối tượng này thường tồn tại lâu hơn một lời gọi phương thức. Cũng gần như không thể dự đoán đối tượng có quá lớn cho stack hay không.

Do đó Ruby dùng loại bộ nhớ kia: heap. Trên heap, chương trình xin một khối bộ nhớ và tự dọn dẹp khi xong. Ruby xin một mảng liền mạch để lưu đối tượng Ruby. Điều này gọi là heap của Ruby.

Tóm tắt Stack và Heap
Bộ nhớ StackRất nhanh
Bộ nhớ dùng được giải phóng tự động khi lời gọi hàm kết thúc
Rất giới hạn kích thước
Bộ nhớ HeapChậm hơn stack một chút
Không dọn dẹp tự động
Kích thước chỉ giới hạn bởi bộ nhớ máy tính

Vậy đối tượng Ruby luôn được cấp phát trên heap của Ruby. Nếu nhỏ hơn 40 byte, nội dung có thể nhúng trực tiếp vào đối tượng. Ngược lại, đối tượng trỏ đến một đoạn bộ nhớ riêng trên heap của Ruby. Vậy đối tượng Ruby thường lưu ở hai vị trí bộ nhớ hoàn toàn khác nhau. Khi heap của Ruby đầy, nó tạo heap mới cho đối tượng mới.

Mark and Sweep (Đánh dấu và Quét dọn)

MRI dùng thuật toán GC gọi là Mark and Sweep. Hoạt động bằng giai đoạn mark trước. Trong giai đoạn mark, Garbage Collector quét tất cả đối tượng hiện có và đặt cờ marked trên mọi đối tượng nó tin là có thể dọn dẹp.

Giai đoạn mark dừng thực thi code. Lý do: Garbage Collector phải hiểu tất cả mối quan hệ giữa các đối tượng. Nếu chương序 chạy trong lúc mark, mọi thứ có thể thay đổi và GC không chắc trạng thái hiện tại của đối tượng.

Sau đó giai đoạn sweep bắt đầu. Chạy nền trên Ruby 1.9 trở lên. Garbage Collector lặng lẽ giải phóng mọi đối tượng được mark ở giai đoạn mark. Bộ nhớ chỉ dùng lại sau khi sweep xong.

Vì giai đoạn mark dừng code, đây là nơi gây vấn đề trong production. Giai đoạn sweep tương đối an toàn.

Tóm tắt Mark and Sweep
Giai đoạn MarkQuét đối tượng hiện có
Đặt cờ mark nếu đối tượng có thể dọn
Dừng thực thi code
Giai đoạn SweepChạy nền
Dọn dẹp đối tượng đã mark
Bộ nhớ dùng lại sau khi sweep xong

Major và Minor GC runs

Từ Ruby 2.1+, Garbage Collector chạy major và minor. Nó theo dõi đối tượng nào mới. Nếu đối tượng sống sót qua vài lần GC, nó được đánh dấu là old. Các đối tượng old bị bỏ qua trong minor runs. Điều này làm minor runs ít xâm nhập hơn vì GC chỉ quét đối tượng vừa cấp phát.

Hữu ích vì thường một phần bộ nhớ không bao giờ bị dọn. Khi boot Rails, nó nạp toàn bộ framework vào bộ nhớ. Đó sẽ ở đó suốt vòng đời, lãng phí tài nguyên nếu kiểm tra mọi đối tượng mỗi lần.

Major và Minor runs
Major runChạy ít hơn
Tốn kém hơn
Minor runBỏ qua đối tượng old
Chạy thường xuyên hơn
Ít xâm nhập hơn

Cho người muốn đi sâu hơn

Chúng ta học nhiều từ blog tuyệt vời của Aman Gupta. Xem đó nếu muốn đi sâu hơn.

Tiếp theo: Điều chỉnh Garbage Collection thực tế

Có một số metrics có thể đo và thay đổi cấu hình để điều chỉnh cách Garbage Collector hoạt động. Phần tiếp theo của series GC này sẽ thảo luận các metrics và tham số cấu hình đó.