Trong tập trước của Ruby Magic, chúng ta đã nói về lý do tại sao chúng ta cần Garbage Collection (GC) và cách thức hoạt động của nó nói chung. Trong bài đăng này, chúng ta sẽ đi sâu hơn một chút về cách điều này được triển khai trong Ruby.
Các triển khai Ruby khác nhau
Có một số cách triển khai của Ruby. Ba cái phổ biến là:MRI (Matz's Ruby Interpreter), Rubinius và JRuby. Các triển khai Ruby khác nhau sử dụng các phương thức khác nhau của GC. Trong bài viết này, chúng tôi sẽ tập trung vào MRI, đây là thứ mà hầu hết các nhà phát triển Ruby sử dụng.
Ruby's heap
Máy tính có hai loại bộ nhớ:Stack và Heap. Ngăn xếp rất nhanh và là cục bộ đối với ngữ cảnh của một lệnh gọi hàm. Điều này có nghĩa là mọi biến được khai báo trong ngăn xếp sẽ được giải phóng ngay lập tức khi hàm được thực hiện. Ngăn xếp có kích thước rất hạn chế, vì vậy, bạn không thể lưu trữ các đối tượng lớn hơn có chứa dữ liệu của hình ảnh hoặc tệp.
Điều này không phù hợp để lưu trữ các đối tượng Ruby. Những đối tượng này thường tồn tại lâu hơn một cuộc gọi phương thức. Ngoài ra, hầu như không thể dự đoán liệu một đối tượng có quá lớn so với ngăn xếp hay không.
Do đó, Ruby sử dụng loại bộ nhớ khác:heap. Trên heap, một chương trình có thể yêu cầu một số bộ nhớ và sau đó chịu trách nhiệm dọn dẹp sau khi hoàn thành với bộ nhớ đó. Ruby sử dụng điều này bằng cách yêu cầu một mảng bộ nhớ duy nhất để sử dụng để lưu trữ các đối tượng Ruby. Đây được gọi là đống của Ruby.
Tóm tắt ngăn xếp và đống | |
---|---|
Bộ nhớ ngăn xếp | Rất nhanh Bộ nhớ đã sử dụng được giải phóng tự động khi lệnh gọi hàm kết thúc Dung lượng rất hạn chế |
Bộ nhớ đống | Chậm hơn một chút so với ngăn xếp Không có tính năng dọn dẹp tự động Kích thước chỉ bị giới hạn bởi bộ nhớ khả dụng của máy tính |
Vì vậy, các đối tượng Ruby luôn được phân bổ trên heap của Ruby. Nếu chúng nhỏ hơn 40 byte, nội dung của chúng có thể được nhúng trực tiếp vào đối tượng. Nếu không, đối tượng trỏ đến một phân đoạn bộ nhớ riêng biệt trên heap của Ruby. Vì vậy, đối tượng Ruby của bạn thường được lưu trữ ở hai vị trí hoàn toàn khác nhau trong bộ nhớ. Khi heap của Ruby đầy, nó sẽ tạo ra một heap mới, được sử dụng cho các đối tượng mới.
Đánh dấu và quét
MRI sử dụng một thuật toán GC được gọi là Mark and Sweep. Điều này hoạt động bằng cách đầu tiên thực hiện một giai đoạn đánh dấu. Trong giai đoạn đánh dấu, Trình thu gom rác sẽ quét tất cả các đối tượng hiện đang tồn tại và đặt cờ được đánh dấu trên mọi đối tượng mà nó tin rằng có thể được dọn sạch.
Giai đoạn đánh dấu tạm dừng việc thực thi mã của bạn. Lý do cho điều này là Garbage Collector phải hiểu tất cả các mối quan hệ giữa các đối tượng tồn tại. Nếu chương trình đang chạy trong quá trình đánh dấu, mọi thứ có thể thay đổi trong thời gian chờ đợi và Trình thu gom rác sẽ không chắc chắn trạng thái hiện tại của đối tượng là gì.
Thứ hai, giai đoạn quét bắt đầu. Điều này chạy trong 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 đánh dấu trong giai đoạn đánh dấu. Bộ nhớ chỉ khả dụng trở lại sau khi quét.
Vì giai đoạn đánh dấu tạm dừng việc thực thi mã của bạn, đây là lúc các vấn đề trong quá trình sản xuất có thể xảy ra. Giai đoạn quét tương đối lành tính.
Đánh dấu và quét tóm tắt | |
---|---|
Đánh dấu giai đoạn | Quét các đối tượng hiện có Đặt cờ đánh dấu nếu đối tượng có thể được làm sạch Tạm dừng thực thi mã |
Giai đoạn quét | Chạy trong nền Dọn dẹp các đối tượng đã đánh dấu Bộ nhớ khả dụng trở lại sau khi quét xong |
Chạy GC chính và phụ
Trong Ruby 2.1+, Garbage Collector thực hiện các lần chạy lớn và nhỏ. Nó theo dõi những đối tượng nào là mới. Nếu một đối tượng sống sót sau một vài lần chạy GC thì nó được đánh dấu là cũ. Các đối tượng cũ sau đó được bỏ qua trong các lần chạy nhỏ. Điều này làm cho phần mềm nhỏ chạy ít bị xâm phạm hơn nhiều vì Bộ thu gom rác chỉ phải quét các đối tượng vừa được cấp phát.
Điều này rất hữu ích vì thường một phần bộ nhớ của bạn không bao giờ được dọn dẹp. Khi bạn khởi động Rails, nó sẽ tải toàn bộ khung công tác Rails vào bộ nhớ. Điều đó sẽ ở đó trong suốt thời gian tồn tại, vì vậy sẽ rất lãng phí tài nguyên để kiểm tra tất cả các đối tượng này mỗi lần.
Vòng chạy chính và phụ | |
---|---|
Hoạt động chính | Chạy ít thường xuyên hơn Chạy nhiều hơn |
Lần chạy nhỏ | Bỏ qua các đối tượng cũ Chạy thường xuyên hơn Chạy ít bị xâm phạm hơn |
Dành cho những ai muốn tìm hiểu sâu hơn
Chúng tôi đã học được rất nhiều điều về điều này từ blog tuyệt vời của Aman Gupta. Hãy kiểm tra nếu bạn muốn tìm hiểu sâu hơn về chủ đề này.
Tiếp theo:Điều chỉnh Thu gom rác thực tế
Có một số chỉ số bạn có thể đo lường và thay đổi cấu hình bạn có thể thực hiện để điều chỉnh cách Công cụ thu gom rác hoạt động. Trong phần tiếp theo của loạt bài GC này, chúng ta sẽ thảo luận về các chỉ số và thông số cấu hình này.