Tôi đã đưa ra câu trả lời này cho một bài đăng tương tự về cùng chủ đề:
Một số người phân bổ có lười biếng không?
Điều này bắt đầu hơi lệch chủ đề (và sau đó tôi sẽ kết hợp nó với câu hỏi của bạn), nhưng những gì đang xảy ra tương tự như những gì xảy ra khi bạn fork một quy trình trong Linux. Khi phân tách, có một cơ chế được gọi là sao chép khi ghi, cơ chế này chỉ sao chép không gian bộ nhớ cho tiến trình mới khi bộ nhớ cũng được ghi. Bằng cách này nếu quá trình phân tách thực thi một chương trình mới ngay lập tức thì bạn đã tiết kiệm được chi phí sao chép bộ nhớ chương trình gốc.
Quay trở lại câu hỏi của bạn, ý tưởng cũng tương tự. Như những người khác đã chỉ ra, yêu cầu bộ nhớ sẽ giúp bạn có không gian bộ nhớ ảo ngay lập tức, nhưng các trang thực tế chỉ được cấp phát khi ghi vào chúng.
Mục đích của việc này là gì? Về cơ bản, nó làm cho bộ nhớ hoạt động không ổn định trở thành một hoạt động thời gian liên tục Big O (1) thay vì một hoạt động Big O (n) (tương tự như cách bộ lập lịch Linux trải nó hoạt động thay vì thực hiện nó trong một đoạn lớn).
Để chứng minh ý tôi, tôi đã làm thử nghiệm sau:
rbarnes@rbarnes-desktop:~/test_code$ time ./bigmalloc
real 0m0.005s
user 0m0.000s
sys 0m0.004s
rbarnes@rbarnes-desktop:~/test_code$ time ./deadbeef
real 0m0.558s
user 0m0.000s
sys 0m0.492s
rbarnes@rbarnes-desktop:~/test_code$ time ./justwrites
real 0m0.006s
user 0m0.000s
sys 0m0.008s
Chương trình bigmalloc phân bổ 20 triệu int, nhưng không làm gì với chúng. deadbeef ghi một số nguyên vào mỗi trang, kết quả là 19531 lần ghi và justwrites phân bổ 19531 số nguyên và số không chúng ra ngoài. Như bạn có thể thấy deadbeef mất khoảng 100 lần để thực thi so với bigmalloc và lâu hơn khoảng 50 lần so với justwrites.
#include <stdlib.h>
int main(int argc, char **argv) {
int *big = malloc(sizeof(int)*20000000);
return 0;
}
.
#include <stdlib.h>
int main(int argc, char **argv) {
int *big = malloc(sizeof(int)*20000000);
for (int* end = big + 20000000; big < end; big += 1024)
*big = 0xDEADBEEF;
return 0;
}
.
#include <stdlib.h>
int main(int argc, char **argv) {
int *big = calloc(sizeof(int), 19531);
return 0;
}