Ủng hộ tôi
Không gian địa chỉ vật lý là không gian địa chỉ thực sự dùng để truy cập chính xác một vị trí trong Bộ nhớ chính (RAM).
Không gian địa chỉ ảo là không gian địa chỉ ảo được tiến trình người dùng sử dụng để truy cập Bộ nhớ ảo (Virtual Memory).
Một địa chỉ ảo bất kỳ có thể được chuyển đổi thành một địa chỉ vật lý bất kỳ (dĩ nhiên là địa chỉ vật lý phải tồn tại), điều này giúp cho mỗi tiến trình sở hữu được không gian địa chỉ ảo của riêng mình và không gian địa chỉ ảo này có thể lớn hơn không gian địa chỉ vật lý.
Quản lý Bộ nhớ là một trong những chức năng thiết yếu của một kernel bên cạnh Quản lý Tiến trình, Lập lịch CPU và Quản lý Nhập/Xuất. Chức năng Quản lý Bộ nhớ được thực hiện bởi Trình quản lý bộ nhớ (Memory Manager) có chức năng cấp phát, thu hồi và bảo vệ bộ nhớ. Để có thể cấp phát và thu hồi bộ nhớ, Trình quản lý bộ nhớ cần biết được tình trạng của bộ nhớ là không gian địa chỉ nào đã được sử dụng và không gian địa chỉ nào đang rảnh. Để thực hiện bảo vệ bộ nhớ, Trình quản lý bộ nhớ sẽ dựa vào các cờ (flag) quy định: chế độ thực thi (người dùng hay kernel), quyền đọc/ghi, ... để quyết định một truy xuất bộ nhớ là hợp lệ hay không.
Các không gian địa chỉ đang rảnh sẽ được dùng để cấp phát cho các cấu trúc dữ liệu được dùng bởi kernel, dữ liệu, mã nhị phân, heap và ngăn xếp (stack) của tiến trình người dùng, ... và sẽ đánh dấu đây là không gian địa chỉ dành riêng cho tiến trình yêu cầu nó.
Một OS có nhiều lớp quản lý bộ nhớ, lớp cao hơn sẽ được xây dựng dựa trên lớp thấp hơn ngay dưới nó. Các lớp quản lý bộ nhớ này bao gồm:
Trình quản lý bộ nhớ vật lý (Physical Memory Manager - PMM) dùng để cấp phát và thu hồi khung trang. PPM này có thể là Trình cấp phát khung trang (Page frame allocator), Trình cấp phát phiến (Slab allocator) và Trình cấp phát bạn thân (Buddy allocator).
Trình quản lý bộ nhớ ảo (Virtual Memory Manager - VMM) dùng để cấp phát và thu hồi trang. Kernel cung cấp 2 lời gọi hệ thống là mmap() và munmap() để phục vụ việc quản lý này.
Trình quản lý không gian người dùng (User-space Manager - UsM) dùng để cấp phát động và thu hồi vùng nhớ Heap của tiến trình người dùng. Thư viện chuẩn của ngôn ngữ C cung cấp 2 hàm là malloc() và free() để phục vụ việc quản lý này.
Theo đó, quy trình sẽ diễn ra khi tiến trình người dùng yêu cầu cấp phát bộ nhớ bao gồm:
Tiến trình người dùng gọi hàm malloc() để yêu cầu UsM cấp phát bộ nhớ. Hàm malloc() sẽ yêu cầu kích thước bộ nhớ được cấp phát theo byte.
UsM kiểm tra xem không gian bộ nhớ mà nó đang giữ có đủ để cấp phát cho tiến trình người dùng hay không? Nếu đủ thì sẽ cấp phát ngay cho tiến trình người dùng và cập nhật trạng thái cấp phát. Nếu không đủ thì sẽ gửi yêu cầu tới VMM để xin thêm trang.
VMM kiểm tra không gian bộ nhớ mà nó đang giữ có đủ để cấp phát cho UsM hay không? Nếu đủ thì sẽ cấp phát ngay cho UsM và cập nhật trạng thái cấp phát. Nếu không đủ thì sẽ gọi thực hiện lời gọi hệ thống mmap() để yêu cầu PMM cấp thêm khung trang.
PMM kiểm tra không gian bộ nhớ mà nó đang giữ có đủ để cấp phát cho VMM hay không? Nếu đủ thì sẽ cấp phát ngay cho VMM, cập nhật trạng thái cấp phát và tiến hành thêm một PTE mới vào Bảng trang. Nếu không đủ thì sẽ phát ra một ngắt để thông báo không thể cấp phát thêm khung trang.
Bộ nhớ ảo (Virtual Memory) là một một mức trừu tượng của Bộ nhớ vật lý. Mục đích của Bộ nhớ ảo là đơn giản hóa việc phát triển ứng dụng người dùng và cho phép các tiến trình người dùng này sử dụng không gian địa chỉ lớn hơn không gian địa chỉ vật lý thực sự có trong máy tính. Không gian địa chỉ được tiến trình người dùng sử dụng được gọi là không gian địa chỉ ảo.
Mục bảng trang (PTE - Pape Table Entry)
Số hiệu trang ảo (VPN - Virtual Page Number)
Số hiệu trang vật lý (PPN - Physical Page Number)
Chuyển đổi địa chỉ
Chuyển đổi địa chỉ là chức năng cốt yếu của Trình quản lý bộ nhớ, Trình quản lý bộ nhớ thực hiện chuyển đổi từ địa chỉ ảo (địa chỉ được tạo ra bởi chương trình ứng dụng người dùng) sang địa chỉ vật lý (địa chỉ thực sự dùng để truy cập Bộ nhớ vật lý). Nhờ việc chuyển đổi này mà không gian địa chỉ vật lý được cấp có thể không cần phải liên tục.
Bảo vệ Bộ nhớ
Trong một Hệ thống Máy tính hiện đại, cùng một lúc có thể có nhiều tiến trình người dùng và tiến trình kernel cùng thực thi. Để tránh các tiến trình người dùng gây nguy hại cho hệ thống và để ngăn cách giữa các tiến trình với nhau thì Trình quản lý bộ nhớ phải kiểm soát quyền truy cập của mỗi tiến trình tới từng địa chỉ vật lý, nhằm ngăn chặn các hành vi tác động không mong muốn tới tiến trình khác.
Cấp phát Bộ nhớ Vật lý
Trình cấp phát khung trang (Page frame allocator)
Có 2 yêu cầu khi cấp phát khung trang đó là:
Không thể cấp phát nhiều hơn số khung trang đang rảnh.
Mỗi lần cấp phát ít nhất 1 khung trang.
Trước khi cấp phát, Trình cấp phát khung trang phải theo dõi tình trạng không gian địa chỉ vật lý để biết khung trang nào đang rảnh (chưa được cấp phát) và khung trang nào đang bận (đã được cấp phát). Một số cách phổ biến để theo dõi tình trạng này là sử dụng danh sách liên kết (linked list), cây (tree), bitmap (chuỗi bit), hệ thống bạn thân (buddy system). Hiện tại Linux đang sử dụng hệ thống bạn thân để theo dõi tình trạng của bộ nhớ vật lý.
Sau khi cấp phát, Trình cấp phát khung trang sẽ trả về địa chỉ vật lý của khung trang đầu tiên. Kế tiếp, kernel sẽ dùng PPN của địa chỉ vật lý này để bổ sung vào PTE trong Bảng trang, từ đó hình thành một ánh xạ địa chỉ tới Bộ nhớ ảo và có thể bắt đầu được truy xuất.
Trình cấp phát bạn thân (Buddy allocator)
Trình cấp phát phiến (Slab allocator)
Khi tạo mới 1 tiến trình, PTB của tiến trình cha sẽ được sao chép cho TLB của tiến trình con, điều này cũng có nghĩa là cũng phải cấp phát không gian địa chỉ vật lý cho tiến trình con (ngoại trừ phần không gian địa chỉ vật lý dùng chung để thực hiện IPC). Nhưng thực tế là tiến trình cha thường không thực hiện thao tác ghi dữ liệu tới toàn bộ không gian địa chỉ vật lý mà nó được cấp (có nghĩa là có những không gian địa chỉ chỉ dành cho việc đọc dữ liệu), khiến cho việc cấp phát thêm khung trang cho tiến trình con là không cần thiết vì cả tiến trình cha và tiến trình con đều có thể dùng chung các không gian địa chỉ dành riêng cho việc đọc này.
Nhằm giải quyết vấn đề tiêu tốn không gian địa chỉ vật lý, cơ chế copy-on-write được ra đời. Với cơ chế copy-on-write, tiến trình cha và tiến trình con cùng chia sẻ toàn bộ không gian địa chỉ vật lý. Nhưng khi có 1 tiến trình muốn ghi dữ liệu vào 1 khung trang nào đó thì khung trang này sẽ được sao chép, lúc này mỗi tiến trình sẽ sở hữu riêng khung trang và tiến trình ghi dữ liệu có thể ghi dữ liệu mà không ảnh hưởng tới tiến trình còn lại. Bằng cách sử dụng cơ chế copy-on-write, chúng ta chỉ tốn thêm phần không gian địa chỉ vật lý dành cho các khung trang bị thay đổi dữ liệu.
LRU là thuật ngữ viết tắt của Least Recently Used (ít được sử dụng gần đây nhất). Thuật toán thay thế khung trang LRU (gọi tắt là RLU) là một thuật toán có hiệu quả gần với thuật toán tối ưu, LRU dựa trên lịch sử truy cập của các khung trang để quyết định khung trang nào nên được chuyển ra ổ đĩa (swap-out) để tạo không gian cấp phát cho các yêu cầu cấp phát mới. Ứng viên được chọn sẽ là khung trang ít được sử dụng gần đây nhất.
Để có thể xác định được khung trang nào ít được sử dụng gần đây nhất thì đòi hỏi phải liên tục sắp xếp danh sách quản lý khung trang đã được cấp phát theo thời gian truy cập khung trang, khung trang nào được sử dụng gần đây nhất thì ở đầu danh sách, khung trang nào ít được sử dụng gần đây nhất thì nằm cuối danh sách. Chi phí cho việc sắp xếp này rất lớn, tuy nhiên nó lại giảm thiểu được số lần swap-out nên đang được sử dụng trong hầu hết các OS ngày nay.
Có thế thiết kế một phần cứng chuyên dụng cho việc tăng tốc LRU. Cách đơn giản nhất là bổ sung vào PTE thêm một trường đếm số lần truy cập khung trang, nghĩa là sẽ cần thiết kế 1 bộ đếm để đếm số lần truy cập khung trang. PTE nào có giá trị đếm nhỏ nhất thì khung trang tương ứng sẽ được chọn làm nạn nhân swap-out khi lỗi trang xảy ra. Trường đếm số lần truy cập khung trang của PTE mới sẽ được nạp trước giá trị bằng giá trị đếm lớn nhất của PTE truy cập gần đây nhất cộng thêm 1. Cách này vô cùng tốn kém vì kích thước của bộ đếm khá lớn và kích thước phần cứng sẽ tăng tuyến tính theo số lượng PTE trong Bảng trang.
Cách thiết kế phần cứng thứ 2 là sử dụng một ma trận vuông, với kích thước NxN được khởi tạo giá trị là 0, với N là số lượng PTE trong Bảng trang. Khi khung trang k được truy cập thì toàn bộ các bit trên hàng k được thiết lập lên 1, sau đó toàn bộ bit trên cột k sẽ bị thiết lập về 0. Hàng nào có giá trị nhỏ nhất là hàng có khung trang tương ứng ít được truy cập gần đây nhất.