Cuộc Cách Mạng Bộ Cấp Phát Bộ Nhớ Của PHK: Cuộc Đấu Tranh Với 4MB RAM Của Một Developer Đã Thay Đổi FreeBSD Mãi Mãi

Nhóm Cộng đồng BigGo
Cuộc Cách Mạng Bộ Cấp Phát Bộ Nhớ Của PHK: Cuộc Đấu Tranh Với 4MB RAM Của Một Developer Đã Thay Đổi FreeBSD Mãi Mãi

Vào giữa những năm 1990, khi giá RAM tăng vọt và hầu hết các developer làm việc với bộ nhớ cực kỳ hạn chế, sự bực bội của một contributor FreeBSD với hệ thống 4MB của mình đã dẫn đến việc tái tưởng tượng hoàn toàn cách các hệ điều hành quản lý cấp phát bộ nhớ. Poul-Henning Kamp , được biết đến với tên PHK , nhận thấy hệ thống của mình liên tục hoạt động với ổ đĩa mỗi khi trình biên dịch GCC kết thúc chạy - một hiện tượng không nên xảy ra khi một chương trình chỉ đơn giản là giải phóng bộ nhớ trước khi tắt.

Thông số kỹ thuật hệ thống của PHK (1994-1995)

  • RAM: 4MB (cực kỳ hạn chế so với thời đại đó)
  • Khối lượng công việc chính: Biên dịch GCC với vai trò kỹ sư phát hành FreeBSD
  • Vấn đề: Tình trạng phân trang quá mức trong quá trình kết thúc chương trình
  • Tiến trình giải pháp: Phát triển trong giai đoạn 1994-1995, commit vào tháng 9 năm 1995

Vấn Đề Gốc Rễ: Bộ Nhớ Ảo Gặp Mã Code Cổ Xưa

Vấn đề nằm ở việc triển khai malloc được kế thừa của FreeBSD từ BSD , dựa trên phương pháp cổ điển được mô tả trong The C Programming Language của Kernighan và Ritchie . Giải pháp tao nhã này hoạt động hoàn hảo trên các hệ thống swapping cũ như PDP-11 , nơi toàn bộ các process hoặc là hoàn toàn trong bộ nhớ hoặc không chạy. Tuy nhiên, các hệ thống bộ nhớ ảo đã thay đổi hoàn toàn cuộc chơi.

Malloc gốc giữ các khối bộ nhớ trống trong một danh sách liên kết, với metadata được lưu trữ ngay tại đầu mỗi chunk trống. Khi giải phóng bộ nhớ, hệ thống phải duyệt qua toàn bộ danh sách này, có khả năng đọc vài từ đầu tiên của mọi khối bộ nhớ không sử dụng. Điều này khiến kernel phải page in bộ nhớ đã nằm không sử dụng trên đĩa, chỉ để đánh dấu nó là trống - tạo ra hiệu ứng death rattle mà PHK quan sát thấy.

Một Hack Thông Minh Gần Như Loại Bỏ Vấn Đề

Giải pháp đầu tiên của PHK tàn bạo nhưng hiệu quả. Thay vì lưu trữ metadata trong các chunk bộ nhớ trống, anh ta sẽ cắt một struct nhỏ từ phía trước của chunk trống đầu tiên trong free list và sử dụng nó để ghi sổ. Điều này có nghĩa là bộ nhớ trống thực sự không bao giờ cần được chạm vào nữa trừ khi nó được cấp phát lại.

Cuộc thảo luận cộng đồng cho thấy sự đánh giá cao đối với cách tiếp cận sáng tạo của PHK , đặc biệt là việc sử dụng symbolic links làm file cấu hình. Thay vì phân tích các file config truyền thống (điều này sẽ yêu cầu malloc phải hoạt động trước), PHK đã sử dụng symbolic links như các file text nhỏ để kiểm soát hành vi malloc trong thời gian chạy.

Các tính năng chính của phkmalloc

  • Tách biệt metadata: Giữ metadata phân bổ tách biệt khỏi các khối bộ nhớ thực tế
  • Bố cục binary buddy: Được sử dụng cho các phân bổ có kích thước nhỏ hơn trang
  • Cấu hình thời gian chạy: Thông qua các liên kết tượng trưng (ví dụ: /etc/malloc.conf -> "AJ")
  • Tăng cường bảo mật: Chống lại các lỗ hổng buffer overflow phổ biến
  • Khả năng debug: Có thể phát hiện double-free, buffer overrun và các lỗi sử dụng malloc khác
Biểu đồ minh họa các cải tiến hiệu suất liên quan đến kỹ thuật phân bổ bộ nhớ của PHK , thể hiện tác động của phương pháp tiếp cận sáng tạo của ông
Biểu đồ minh họa các cải tiến hiệu suất liên quan đến kỹ thuật phân bổ bộ nhớ của PHK , thể hiện tác động của phương pháp tiếp cận sáng tạo của ông

Lợi Ích Bảo Mật và Hạn Chế Multi-Core

Bằng cách tách metadata khỏi các chunk bộ nhớ, phkmalloc trở nên đáng ngạc nhiên kháng lại các cuộc tấn công buffer overflow. Cộng đồng lưu ý rằng điều này dẫn đến nhiều advisory bảo mật đề cập rằng Linux , Solaris ... dễ bị tấn công, nhưng FreeBSD thì không. Mặc dù PHK nhấn mạnh rằng phkmalloc vẫn có thể bị xâm phạm, nó mua cho các quản trị viên hệ thống vài tháng thay vì vài giờ để vá lỗ hổng.

Tuy nhiên, khi các hệ thống multi-threading và multi-CPU trở nên phổ biến, các cấu trúc dữ liệu được tích hợp chặt chẽ của phkmalloc yêu cầu một mutex lớn duy nhất xung quanh tất cả các hoạt động. Điều này hoạt động tốt cho một hoặc hai CPU nhưng trở thành nút thắt hiệu suất với bốn core trở lên.

Kết quả So sánh Hiệu suất

  • Hiệu suất: Tương đương với GNU malloc khi có đủ RAM
  • Hiệu quả bộ nhớ: Hiệu suất xuất sắc với RAM hạn chế (8MB trở xuống)
  • Hạn chế đa lõi: Yêu cầu mutex đơn, trở thành nút thắt cổ chai ở 4+ lõi
  • Phiên bản kế thừa: Cuối cùng được thay thế bởi jemalloc để hỗ trợ đa luồng tốt hơn

Tính Liên Quan Hiện Đại và Thách Thức NUMA

Cuộc thảo luận ngày nay đề cập đến việc liệu các hệ thống NUMA hiện tại với hàng trăm core có đáng để thiết kế lại hoàn toàn tương tự như cuộc cách mạng của PHK hay không. Các allocator hiện đại như jemalloc giải quyết các vấn đề multi-core với per-CPU arenas, mặc dù điều này có thể tạo ra các vấn đề mới khi các thread bị park hoặc ngừng cấp phát bộ nhớ - bộ nhớ được cấp phát của chúng có thể không bao giờ được trả lại cho hệ thống.

Câu chuyện của phkmalloc chứng minh cách các ràng buộc phần cứng thúc đẩy đổi mới phần mềm. Điều bắt đầu như sự bực bội của một developer với hệ thống 4MB đã trở thành một cải tiến nền tảng ảnh hưởng đến quản lý bộ nhớ trên nhiều hệ điều hành và giúp thiết lập các thực hành bảo mật tốt hơn vẫn còn liên quan đến ngày nay.

Tham khảo: phkmalloc