Cấp phát heap đơn lẻ từng đối tượng qua heap.alloc là một mô hình quen thuộc, nhưng ở tầng hệ thống, nó có hai nhược điểm: tốc độ chậm do phải tìm kiếm trong phân mảnh bộ nhớ (heap fragmentation), và nguy cơ leak cao khi hệ thống phức tạp dần. Đôi khi, chúng ta có một nhóm lớn các đối tượng cùng được sinh ra phục vụ cho một phiên làm việc (như toàn bộ AST của một file đang được parse) và chúng nên cùng chết đi khi phiên làm việc kết thúc.
Sprint 15 đưa vào DUY khái niệm region — vùng nhớ tập thể.
let arena = region.new()
let node = arena.alloc_view(32)
Một region hoạt động như một arena allocator. Khi anh cấp phát trong một region, việc cấp phát chỉ đơn giản là tăng một con trỏ vùng nhớ (bump allocation) — cực kỳ nhanh. Khi region đi ra khỏi scope, toàn bộ vùng nhớ khổng lồ đó được giải phóng cùng một lúc bằng một lệnh giải phóng đơn lẻ.
Nhưng sự nguy hiểm lớn nhất của arena là dangling references: một view trỏ vào bộ nhớ của region có thể vô tình bị trả về ra ngoài hàm sau khi region đã bị hủy. Đó gọi là hiện tượng view escape.
Để ngăn chặn điều này, Sprint 15 xây dựng quy tắc R-VIEW-3 (escape checking). Compiler theo dõi chặt chẽ xuất xứ của mỗi view. Nếu view đó được sinh ra từ lệnh arena.alloc_view, nó mang gene của arena. Khi gặp lệnh return v, compiler kiểm tra xem region sinh ra v có outlive hàm hiện tại hay không. Nếu không, compilation lập tức bị hủy bỏ kèm lỗi:
may outlive region
Tôi nhớ lúc chạy thử nghiệm kernel với region lần đầu tiên, tôi đã cố tình trả về một node AST ra ngoài scope chứa arena. Compiler đã lập tức từ chối và chỉ ra chính xác dòng code vi phạm. Cảm giác lúc đó giống như bạn đang đi trên một con đường trơn trượt nhưng biết chắc chắn có một bức tường thép bảo vệ mình phía sau. Chúng tôi chấp nhận việc region giữ lại bộ nhớ của các đối tượng chết lâu hơn cần thiết, làm tăng đỉnh bộ nhớ tạm thời (memory peak), để đổi lấy sự an toàn tuyệt đối và hiệu năng cấp phát cực cao.
Bình luận (0)
Đang tải bình luận...