Phần 9.6 "Overcommit và OOM" trong tài liệu mà @dunxd đề cập là đặc biệt đồ họa về sự nguy hiểm của việc cho phép overcommit. Tuy nhiên, 80
trông tôi cũng thú vị, vì vậy tôi đã tiến hành một vài thử nghiệm.
Những gì tôi tìm thấy là overcommit_ratio
ảnh hưởng đến tổng RAM có sẵn cho TẤT CẢ các quy trình. Các quy trình root dường như không được đối xử khác với các quy trình người dùng thông thường.
Đặt tỷ lệ thành 100
hoặc ít hơn sẽ cung cấp ngữ nghĩa cổ điển trong đó các giá trị trả về malloc/sbrk
là đáng tin cậy. Đặt tỷ lệ thấp hơn 100
có thể là một cách để dự trữ thêm RAM cho các hoạt động không xử lý như bộ nhớ đệm và vv.
Vì vậy, trên máy tính của tôi có 24 GiB RAM, bị vô hiệu hóa trao đổi, 9 GiB đang sử dụng, top
hiển thị
Mem: 24683652k total, 9207532k used, 15476120k free, 19668k buffers
Swap: 0k total, 0k used, 0k free, 241804k cached
Dưới đây là một số overcommit_ratio
cài đặt và mức độ RAM mà chương trình người tiêu dùng ram của tôi có thể lấy (chạm vào từng trang) - trong mỗi trường hợp, chương trình thoát ra một cách sạch sẽ một lần malloc
thất bại.
50 ~680 MiB
60 ~2900 MiB
70 ~5200 MiB
100 ~12000 MiB
Chạy nhiều lần cùng một lúc, ngay cả với một số người dùng root, đã không thay đổi tổng số tiền họ tiêu thụ cùng nhau. Thật thú vị khi nó không thể tiêu thụ 3+ GiB cuối cùng; những free
không thả hơn nhiều so gì được hiển thị ở đây:
Mem: 24683652k total, 20968212k used, 3715440k free, 20828k buffers
Các thử nghiệm rất lộn xộn - bất cứ điều gì sử dụng malloc tại thời điểm tất cả RAM đang sử dụng đều có xu hướng bị sập, vì nhiều lập trình viên rất tệ trong việc kiểm tra lỗi malloc trong C, một số thư viện bộ sưu tập phổ biến bỏ qua hoàn toàn, và C ++ và nhiều ngôn ngữ khác thậm chí còn tệ hơn
Hầu hết các triển khai ban đầu của RAM tưởng tượng mà tôi thấy là xử lý một trường hợp rất cụ thể, trong đó một quy trình lớn duy nhất - nói 51% + bộ nhớ khả dụng - cần thiết để fork()
thực hiện exec()
một số chương trình hỗ trợ, thường là một chương trình nhỏ hơn nhiều. Các hệ điều hành với ngữ nghĩa sao chép khi ghi sẽ cho phép fork()
, nhưng với điều kiện là nếu quá trình rẽ nhánh thực sự cố gắng sửa đổi quá nhiều trang bộ nhớ (mỗi trang sẽ phải được khởi tạo thành một trang mới độc lập với quy trình lớn ban đầu) nó sẽ bị giết Quá trình cha mẹ chỉ gặp nguy hiểm nếu phân bổ thêm bộ nhớ và có thể xử lý hết, trong một số trường hợp chỉ cần chờ một chút để một quá trình khác chết, và sau đó tiếp tục. Quá trình con thường chỉ thay thế nó bằng một chương trình (thường nhỏ hơn) thông quaexec()
và sau đó được miễn phí của proviso.
Khái niệm overcommit của Linux là một cách tiếp cận cực đoan để cho phép cả hai fork()
xảy ra cũng như cho phép các quy trình đơn lẻ được tổng thể hóa một cách ồ ạt. Trường hợp tử vong oom-killer-gây ra xảy ra không đồng bộ, thậm chí để chương trình làm phân bổ bộ nhớ xử lý trách nhiệm. Cá nhân tôi ghét sự quá tải trên toàn hệ thống nói chung và kẻ giết người nói riêng - nó thúc đẩy cách tiếp cận ma quỷ có thể quan tâm đến việc quản lý bộ nhớ lây nhiễm các thư viện và thông qua chúng mọi ứng dụng sử dụng chúng.
Tôi khuyên bạn nên đặt tỷ lệ thành 100 và có phân vùng trao đổi cũng thường chỉ được sử dụng bởi các quy trình lớn - thường chỉ sử dụng một phần rất nhỏ của chính chúng bị nhồi vào trao đổi, và do đó bảo vệ phần lớn các quy trình khỏi hành vi giết người OOM. Điều này sẽ giữ cho máy chủ web của bạn an toàn khỏi cái chết ngẫu nhiên và nếu nó được viết để xử lý có malloc
trách nhiệm, thậm chí an toàn khỏi việc tự sát (nhưng không đặt cược vào cái sau).
Điều đó có nghĩa là tôi đang sử dụng cái này trong /etc/sysctl.d/10-no-overcommit.conf
vm.overcommit_memory = 2
vm.overcommit_ratio = 100