Phân Tích Mã Nguồn Lua GC (5)
Hôm nay chúng ta hãy cùng tìm hiểu về write barrier – một thành phần quan trọng trong cơ chế thu gom rác của Lua. Trong quá trình quét bộ nhớ, do việc xử lý được chia thành nhiều giai đoạn, sẽ có những lúc các đối tượng vừa được đánh dấu thành màu đen nhưng lại bị sửa đổi lại – khiến chúng cần phải được đánh dấu lại. Để giải quyết vấn đề này, hệ thống phải thiết lập một rào chắn ghi (write barrier) mỗi khi có thao tác chỉnh sửa đối tượng. Những thay đổi này sẽ đảm bảo các đối tượng liên quan được đánh dấu màu chính xác, hoặc được ghi lại vào danh sách để xử lý ở giai đoạn atomic cuối cùng của quá trình đánh dấu.
Hệ thống có 4 macro API liên quan đến barrier, được định nghĩa tại dòng 86 của file lgc.h
:
|
|
-
luaC_barrier
vàluaC_objbarrier
có chức năng tương tự nhau, nhưng khác nhau ở kiểu dữ liệu đầu vào:luaC_barrier
xử lý các giá trị kiểu TValue (giống như biến lưu trữ giá trị tổng quát trong Lua),luaC_objbarrier
xử lý các đối tượng thuộc lớp GCObject (đối tượng có thể bị thu gom rác).
Cả hai đều dùng để thiết lập mối liên kết giữav
vàp
khiv
đang ở trạng thái trắng (white) vàp
đã là đen (black), từ đó gọi hàmluaC_barrierf
.
-
luaC_barriert
vàluaC_objbarriert
thì được dùng khi thiết lập mối liên kết giữav
vàt
, gọi đếnluaC_barrierback
nếu điều kiện tương tự (v trắng, t đen) thỏa mãn.
Tại sao bảng (table) được xử lý đặc biệt?
Bảng trong Lua có cấu trúc tham chiếu 1-đến-N, nghĩa là một bảng có thể chứa rất nhiều phần tử và thường xuyên bị chỉnh sửa. Trong khi đó, các kiểu dữ liệu khác như closure hay thread có mối liên kết hạn chế hơn. Việc xử lý riêng bảng giúp tối ưu hiệu năng của cơ chế barrier, giảm thiểu chi phí tính toán không cần thiết.
Chi tiết về luaC_barrierf
Hàm luaC_barrierf
(định nghĩa tại dòng 663 của lgc.c
) đảm nhiệm việc đánh dấu ngay lập tức các đối tượng mới thiết lập mối liên kết. Mã nguồn của nó như sau:
|
|
Tóm lại:
- Nếu GC đang ở trạng thái
GCSpropagate
(giai đoạn đánh dấu),v
sẽ được đánh dấu bằng hàmreallymarkobject
. - Ngược lại, đối tượng
o
sẽ bị chuyển về màu trắng để tránh các barrier gọi lặp lại trong tương lai. Kỹ thuật này tận dụng cơ chế “hai màu trắng” (double-white) của Lua – giúp giảm thiểu số lần gọi barrier doo
không còn là màu đen.
Vai trò của luaC_barrierback
Hàm luaC_barrierback
(dòng 676 lgc.c
) đưa các bảng bị chỉnh sửa trở lại danh sách grayagain, để xử lý ở giai đoạn atomic:
|
|
Danh sách grayagain
sẽ được xử lý toàn bộ ở giai đoạn atomic. Việc chuyển bảng về màu xám (gray) giúp ngăn chặn các lần gọi liên tiếp luaC_barrierback
khi bảng tiếp tục bị sửa đổi.
Xử lý các bảng yếu (weak table)
Các bảng yếu không bao giờ gọi luaC_barrierback
vì hai lý do:
- Bảng yếu không thể tồn tại ở trạng thái đen.
- Mỗi GCObject chỉ có thể nằm trong một danh sách duy nhất. Bảng yếu đã được liên kết vào danh sách
weak
nên không thể thêm vàograyagain
.
Đoạn mã tại dòng 285 lgc.c
giải thích điều này:
|
|
Tại sao phải đánh dấu lại (remark) các bảng yếu?
Bảng yếu có thể là key-weak, value-weak, hoặc cả hai. Trong quá trình quét, các sửa đổi trên bảng yếu không kích hoạt barrier, có thể khiến một số mối quan hệ “mạnh” (strong) bị ẩn trong bảng. Do đó,