Malloc có lười biếng tạo các trang hỗ trợ để phân bổ trên Linux (và các nền tảng khác) không?


75

Trên Linux, nếu tôi muốn malloc(1024 * 1024 * 1024), thì malloc thực sự làm gì?

Tôi chắc chắn rằng nó chỉ định một địa chỉ ảo cho phân bổ (bằng cách xem danh sách miễn phí và tạo một ánh xạ mới nếu cần), nhưng nó có thực sự tạo ra các trang hoán đổi trị giá 1 GiB không? Hay đó mprotectlà phạm vi địa chỉ và tạo các trang khi bạn thực sự chạm vào chúng như thế mmapnào?

(Tôi chỉ định Linux vì tiêu chuẩn này không nói về những loại chi tiết này, nhưng tôi cũng muốn biết các nền tảng khác làm gì.)


2
Câu hỏi thú vị; Tôi cũng rất tò mò về hành vi trên các nền tảng khác, nhưng kudo vì đã khóa câu hỏi này xuống Linux.
Paul Sonier

đã có lúc điều này dường như là rất nhiều kỷ niệm ...
Sled

Câu trả lời:


43

Linux thực hiện phân bổ trang hoãn lại, hay còn gọi là. 'phân bổ bộ nhớ lạc quan'. Bộ nhớ bạn lấy lại từ malloc không được sao lưu bởi bất kỳ thứ gì và khi bạn chạm vào nó, bạn thực sự có thể gặp phải tình trạng OOM (nếu không có không gian hoán đổi cho trang bạn yêu cầu), trong trường hợp đó, một quá trình bị chấm dứt một cách ngẫu nhiên .

Xem ví dụ: http://www.linuxdevcenter.com/pub/a/linux/2006/11/30/linux-out-of-memory.html


5
Thật thú vị khi xem cách hạt nhân tính toán "độ xấu" của một tiến trình để tìm ra (các) tiến trình nào sẽ giết khi hết bộ nhớ.
JesperE

IIRC nó có các cấp: Cao nhất đến thấp nhất - Các quy trình gốc, quy trình thực hiện I / O, quy trình ngủ ... thấp nhất lấy đạn.
Aiden Bell

@Aiden Chức năng "badness" được sử dụng để xác định quá trình cần giết được mô tả trong liên kết.
Aaron Maenpaa

1
Hành vi OOM muộn không phải lúc nào cũng đúng; nó phụ thuộc vào cài đặt overcommit. Xem kernel.org/doc/Documentation/vm/overcommit-accounting để biết ba chế độ.
ZachB

16

9. Bộ nhớ (một phần của nhân Linux , Một số nhận xét về nhân Linux của Andries Brouwer) là một tài liệu tốt.

Nó chứa các chương trình sau đây chứng minh khả năng xử lý bộ nhớ vật lý so với bộ nhớ thực của Linux và giải thích phần bên trong của hạt nhân.

Thông thường, chương trình demo đầu tiên sẽ nhận được một lượng bộ nhớ rất lớn trước khi hàm malloc () trả về NULL. Chương trình demo thứ hai sẽ nhận được một lượng bộ nhớ nhỏ hơn nhiều, bây giờ bộ nhớ lấy được trước đó đã thực sự được sử dụng. Chương trình thứ ba sẽ nhận được cùng một lượng lớn như chương trình đầu tiên, và sau đó nó sẽ bị giết khi nó muốn sử dụng bộ nhớ của mình.

Chương trình demo 1: cấp phát bộ nhớ mà không cần sử dụng nó.

Chương trình demo 2: cấp phát bộ nhớ và thực sự chạm vào tất cả.

Chương trình demo 3: cấp phát trước và sử dụng sau.

(Trên một hệ thống hoạt động tốt, như Solaris , ba chương trình demo có cùng dung lượng bộ nhớ và không bị lỗi, nhưng hãy xem hàm malloc () trả về NULL.)


6
"hoạt động tốt" là một vấn đề của ý kiến. Trên thực tế, Linux có các tùy chọn trong / proc / sys / vm để kiểm soát hành vi gửi quá mức. Bạn có thể có nó như Solaris có nó nếu bạn muốn.
Zan Lynx

2
Hãy cảnh báo, / proc / sys / vm luôn bị BROKEN !! groups.google.com/group/comp.os.linux.development.system/… Đây là MẸO TỐT CHO HIỆU SUẤT LINUX VÀ Đĩa . Nếu bạn đã từng thực hiện một bản sao lớn và rất nhiều bộ nhớ đệm đang bị sử dụng và hệ thống I / O của bạn bắt đầu bị hỏng .... echo 1> / proc / sys / vm / drop_caches thì hãy thay đổi trước khi sao lưu thông lượng cao :) đi con số !!
RandomNickName42

11

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.

.

.


6

Malloc phân bổ bộ nhớ ra khỏi các khối do libc quản lý. Khi cần thêm bộ nhớ, thư viện sẽ chuyển đến hạt nhân bằng lệnh gọi hệ thống brk.

Kernel cấp phát các trang của bộ nhớ ảo cho quá trình gọi. Các trang được quản lý như một phần của tài nguyên thuộc sở hữu của quy trình. Các trang vật lý không được cấp phát khi bộ nhớ không hoạt động. Khi quá trình truy cập vào bất kỳ vị trí bộ nhớ nào ở một trong các trang brk'd thì xảy ra lỗi trang. Kernel xác nhận rằng bộ nhớ ảo đã được cấp phát và tiến hành ánh xạ một trang vật lý sang trang ảo.

Việc phân bổ trang không bị giới hạn trong việc viết và hoàn toàn khác biệt với việc sao chép khi viết. Mọi truy cập, đọc hoặc ghi, đều dẫn đến lỗi trang và ánh xạ trang vật lý.

Lưu ý rằng bộ nhớ ngăn xếp được ánh xạ tự động. Có nghĩa là, một brk rõ ràng không bắt buộc phải ánh xạ các trang tới bộ nhớ ảo được ngăn xếp sử dụng.


Lưu ý rằng glibc đáp ứng các phân bổ lớn bằng cách mmaping các trang ẩn danh thay vì sử dụng brk. Xem gnu.org/software/libc/manual/html_node/The-GNU-Allocator.html .
ZachB

5

Trên Windows, các trang được cam kết (nghĩa là bộ nhớ trống có sẵn sẽ giảm), nhưng chúng sẽ không thực sự được cấp phát cho đến khi bạn chạm vào các trang (đọc hoặc ghi).


2

Trên hầu hết các hệ thống giống Unix, nó quản lý ranh giới brk . VM thêm các trang khi bị bộ xử lý tác động. Ít nhất Linux và BSDs làm được điều này.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.