1. KERNEL SPACE VÀ USER SPACE
Memory ( bộ nhớ ) đề cập đến các mạch tích hợp phần cứng máy tính, cái mà lưu trữ thông tin cho máy tính có thể sử dụng ngay. Bộ nhớ máy tính được xây dựng để lưu trữ các mẫu bit (bit patterns). Không chỉ data mà các câu lệnh ( bản chất đều được máy tính đọc dưới dạng các bit ) và có thể được lưu trữ trong bộ nhớ.
Vậy đặt ra câu hỏi, chúng được lưu trữ như thế nào?
Trong systems software (phần mềm hệ thống), chúng được lưu trữ trong các đoạn bộ nhớ (segment of memory) riêng biệt. Và các phân đoạn này cũng dược chia theo data và program type.
Hệ điều hành đã nhiệm ( multitasking OS runs ) chạy trong không gian địa chỉ ảo ( virtual address space ). Trong trường hợp hệ thống là 64-bit, địa chỉ bộ nhớ được phân bổ là 8 bytes, 4 bytes cho hệ thống 32-bit và 2 bytes hệ thống 16-bit. Giá trị này gọi là kích thước địa chỉ, đơn vị nhỏ nhất mà CPU có thể định địa chỉ là 1 byte ( 8 bit ).
Khi chương trình chạy, quá trình xử lý được thực hiện ở 2 không gian gọi là Kernel Space và User Space trên hệ thống ( 2 không gian này được chia ra từ bộ nhớ ảo ). Hai không gian này ngầm can thiệp lẫn nhau và quá trình xử lý chương trình được tiến hành.
Lý do chính cho sự tách biệt này là để bảo vệ bộ nhớ và phần cứng khỏi hành vi sai trái của phần mềm độc hại hoặc bên thứ 3
- Kernel Space
Không gian Kernel chỉ có thể truy cập bởi các tiến trình của người dùng thông qua việc sử dụng các câu lệnh System calls ( hiểu đơn giản là 1 số câu lệnh đọc ghi xuống trực tiếp Kernel Space ), lệnh gọi này là các yêu cầu trong hệ điều hành giống Unix, chẳng hạn như đầu vào/ đầu ra (I/O) hoặc tạo process.
Đây là không gian dành riêng để chạy trình điều khiển thiết bị.
- User Space
Không gian người dùng là tài nguyên tính toán được phân bổ cho người dùng và đó là tài nguyên mà chương trình thực thi có thể truy cập trực tiếp. Không gian này có thể được phận loại thành 1 số phân đoạn (segments) (nằm ở RAM)
MEMORY LAYOUT chúng ta tìm hiểu là ở phần này
Nói thêm:
- Mối quan hệ giữa Kernel Space và User Space:
Một trong những vai trò của kernel là quản lý tất cả các tiền trình (process, thread) hoặc ứng dụng của người dùng (user) trong User Space
CPU rings
Các CPU rings là điểm phân biệt rõ ràng nhất giữa Kernel Space và User Space
CPU rings là các lớp giữa các ứng dụng được cài đặt trên hệ thống máy tính và các core process (tiến trình cốt lõi) của hệ thống. Những cấu trúc rings này dùng để bảo vệ các process khỏi bị can thiệp.
Khi bạn ở chế độ được bảo vệ x86, CPU luôn ở một trong 4 vòng. Ví dụ: kernel Linux chỉ sử dụng 0 và 3:
- Ring 0 cho Kernel Space.
- Ring 3 cho User Space.
Kernel Space | User Space |
---|---|
Kernels và OS core thực thi ở đây | Program và các ứng dụng bình thường chạy ở đây |
Đây là không gian cốt lõi của hệ điều hành (OS) | Đó là dạng sand-boxing nhằm hạn chế quá trình người dùng truy cập vào OS kernel |
Nó có toàn quyền truy cập vào tất cả bộ nhớ | Nó có quyền truy cập hạn chế vào bộ nhớ và chỉ truy cập Kernel thông qua System Call |
Nó chứa page table cho process, cấu trúc dữ liệu kernel. thread và kernel code | Nó bao gồm program code, data, stacks, and heap của tiến trình |
2. MEMORY LAYOUT IN PROGRAM
Hình ảnh sau đây hiển thị không gian bộ nhớ ảo của Kernel Space và User Space. Phần User Space được phân loại thành Space, Heap, BSS, Data và Text.
Stack:
Không gian Stack (ngăn xếp) nằm ngay dưới Kernel Space, thường đối diện với vùng Heap và phát triển xuống các địa chỉ thấp hơn (nó có thể phát triển theo hướng ngược lại trên một số kiến trúc khác).
Stack (Ngăn xếp) là cấu trúc dữ liệu LIFO (vào trước ra trước). Trong khoa học máy tính, ngăn xếp là một kiểu dữ liệu trừu tượng đóng vai trò là tập hợp các phần tử, với hai thao tác chính:
- push: thêm 1 phần tử
- pop: loại bỏ phần tử được thêm gần đây nhất nhưng chưa bị xóa
Khu vực này được dành để lưu trữ tất cả dữ liệu cần thiết cho lệnh gọi hàm trong một chương trình. Việc gọi một hàm cũng giống như việc push sự kiện thực thi lời gọi hàm (called function execution) lên trên cùng của ngăn xếp và khi hàm đó hoàn thành, kết quả sẽ được trả về khi đưa hàm ra khỏi ngăn xếp. Tập dữ liệu dành cho việc đẩy 1 lệnh gọi hàm vào stack được đặt tên là stack frame và chứa dữ liệu sau:
- các đối số (giá trị tham số) được truyền vào routine (thủ tục, ngăn của stack)
- địa chỉ trả về cho lời gọi của routine (routine's caller)
- không gian cho các biến cục bộ của routine
VD về STACK:
int main() { int result = getResult();
}
int getResult() { int num1 = getNum1(); int num2 = getNum2(); return num1 + num2;
}
int getNum1() { return 10;
}
int getNum2() { return 20;
}
Các bước hoạt động của chương trình trên đối với vùng nhớ stack
Note: Tóm lại vùng nhớ này lưu trữ local variable (biến cục bộ), chứa giá trị của tham số khi được gọi đến, ...
HEAP
Heap là phân đoạn thường diễn ra việc phân bổ** bộ nhớ động**. Vùng này thường bắt đầu ở cuối phân đoạn BSS và phát triển lên tới các địa chỉ bộ nhớ cao hơn. Trong C, nó được quản lý bởi malloc / new, free / delete, sử dụng lệnh gọi brk và sbrksystem để điều chỉnh kích thước của nó.
Việc phân bổ vùng heap xảy ra trong các trường hợp sau:
- kích thước bộ nhớ được phân bổ động vào thời gian chạy
- phạm vi không bị giới hạn. (ví dụ: các biến được tham chiếu từ nhiều nơi)
- kích thước bộ nhớ rất lớn.
Trách nhiệm của chúng ta là giải phóng bộ nhớ trên heap. Các đối tượng trên heap dẫn đến** rò rỉ bộ nhớ** nếu chúng không được giải phóng. Trong các ngôn ngữ thu gom rác, trình thu gom rác sẽ giải phóng bộ nhớ trên heap và ngăn ngừa rò rỉ bộ nhớ.
BSS ( Block Started by Symbol )
Phân đoạn dữ liệu chưa được khởi tạo, thường được gọi là phân đoạn BSS. Dữ liệu trong phân đoạn này được kernel khởi tạo thành số học 0 trước khi chương trình bắt đầu thực thi. Ví dụ: một biến được khai báo là static int i; sẽ được phân bổ vào phân đoạn BSS.
Data
Phân đoạn dữ liệu chứa các biến toàn cục và tĩnh được khởi tạo có giá trị được xác định trước và có thể được sửa đổi. nó được chia thành không gian chỉ đọc và không gian đọc-ghi.
Text
Một phân đoạn trong đó lệnh ngôn ngữ máy được lưu trữ. Phân đoạn này là không gian chỉ đọc
Stack vs Heap
Ngăn xếp nhanh hơn vì mẫu truy cập khiến việc phân bổ và giải phóng bộ nhớ khỏi nó trở nên đơn giản (một con trỏ/số nguyên chỉ đơn giản là tăng hoặc giảm), trong khi vùng heap có công việc ghi sổ phức tạp hơn nhiều liên quan đến việc phân bổ hoặc giải phóng. Ngoài ra, mỗi byte trong ngăn xếp có xu hướng được sử dụng lại rất thường xuyên, điều đó có nghĩa là nó có xu hướng được ánh xạ tới bộ đệm của bộ xử lý, khiến nó hoạt động rất nhanh. Một điểm nhấn khác về hiệu suất của heap là heap, chủ yếu là tài nguyên toàn cầu, thường phải an toàn đa luồng, tức là mỗi phân bổ và phân bổ cần phải - thường - được đồng bộ hóa với "tất cả" các truy cập heap khác trong chương trình.