Làm cách nào để nhanh chóng dừng quá trình gây ra sự cố (do phân bổ bộ nhớ dư thừa)?


19

Tất cả chúng ta đều đã trải nghiệm nó - một số chương trình được yêu cầu làm một cái gì đó đòi hỏi một lượng lớn bộ nhớ. Nó mạnh dạn cố gắng phân bổ tất cả bộ nhớ này, và hệ thống ngay lập tức bắt đầu đập, hoán đổi vô tận và trở nên chậm chạp hoặc không phản hồi.

Gần đây nhất tôi đã trải nghiệm điều này trên máy tính xách tay Ubuntu của mình do tập lệnh Matlab đang cố gắng phân bổ một ma trận khổng lồ lố bịch. Sau ~ 5 phút ném, tôi đã có thể Ctrl-F1 đến bàn điều khiển và giết Matlab. Tôi muốn có một số phím nóng sẽ cho tôi quyền kiểm soát hệ thống ngay lập tức và cho phép tôi tiêu diệt quá trình vi phạm; hoặc, có lẽ, chỉ đơn giản là âm thầm từ chối phân bổ một bộ đệm lớn như vậy.

  1. Cách nhanh nhất để lấy lại quyền kiểm soát hệ thống Linux đã trở nên không phản hồi hoặc cực kỳ chậm chạp do hoán đổi quá mức là gì?

  2. Có cách nào hiệu quả để ngăn chặn sự hoán đổi đó xảy ra ở nơi đầu tiên, chẳng hạn như bằng cách giới hạn dung lượng bộ nhớ mà một quy trình được phép thử phân bổ?

Câu trả lời:


12

Nhấn Alt-SysRq-F để hủy quá trình sử dụng nhiều bộ nhớ nhất:

  • Khóa SysRq thường được ánh xạ tới phím In.
  • Nếu bạn đang sử dụng máy tính để bàn đồ họa, bạn có thể cần nhấn Ctrl-Alt-SysRq-F trong trường hợp nhấn Alt-SysRq sẽ kích hoạt một hành động khác (ví dụ: chương trình chụp nhanh).
  • Nếu bạn đang sử dụng máy tính xách tay, bạn cũng có thể cần phải bấm phím chức năng.
  • Để biết thêm thông tin đọc bài viết trên wikipedia .

5

Tôi đã tạo một kịch bản cho mục đích này - https://github.com/tobixen/thrash-protect

Tôi đã có kịch bản này chạy trên các máy chủ sản xuất, máy trạm và máy tính xách tay rất thành công. Kịch bản này không giết chết các quy trình, nhưng tạm ngưng chúng - tôi đã có một vài tình huống sau đó tôi chắc chắn rằng mình đã mất kiểm soát do bị đập nếu không có kịch bản đơn giản này. Trong trường hợp "tệ nhất", quá trình vi phạm sẽ bị chậm lại rất nhiều và cuối cùng bị giết bởi kernel (OOM), trong trường hợp "tốt nhất", quá trình vi phạm sẽ thực sự hoàn tất ... trong mọi trường hợp, máy chủ hoặc máy trạm sẽ vẫn tương đối nhạy bén để dễ dàng điều tra tình hình.

Tất nhiên, "mua thêm bộ nhớ" hoặc "không sử dụng trao đổi" là hai câu trả lời thay thế, truyền thống hơn cho câu hỏi "làm thế nào để tránh bị đập?", Nhưng nói chung chúng có xu hướng không hoạt động tốt (cài đặt thêm bộ nhớ không tầm thường, một quá trình lừa đảo có thể ăn hết bộ nhớ cho dù người ta đã cài đặt bao nhiêu và người ta có thể gặp vấn đề về sự cố ngay cả khi không trao đổi khi không có đủ bộ nhớ để đệm / bộ đệm). Tôi khuyên bạn nên sử dụng thrash-bảo vệ cộng với nhiều không gian trao đổi.


Về việc vô hiệu hóa trao đổi, theo unix.stackexchange.com/a/24646/9108 nó có thể không phải là lựa chọn tốt nhất.
sashoalm

Thật vậy, có ai đó đã nhận xét tương tự với tôi, vì vậy tôi đã sửa đổi tài liệu chống giật ở thời điểm đó.
tobixen

4
  1. Cách nhanh nhất để lấy lại quyền kiểm soát hệ thống Linux đã trở nên không phản hồi hoặc cực kỳ chậm chạp do hoán đổi quá mức là gì?

Đã trả lời ở trên với Alt-SysRq-F

  1. Có cách nào hiệu quả để ngăn chặn sự hoán đổi đó xảy ra ở nơi đầu tiên, chẳng hạn như bằng cách giới hạn dung lượng bộ nhớ mà một quy trình được phép thử phân bổ?

Tôi đang trả lời phần 2 này. Có, ulimitvẫn hoạt động đủ tốt để giới hạn một quy trình duy nhất. Bạn có thể:

  • đặt giới hạn mềm cho một quy trình mà bạn biết có thể sẽ vượt khỏi tầm kiểm soát
  • đặt giới hạn cứng cho tất cả các quy trình nếu bạn muốn có thêm bảo hiểm

Ngoài ra, như đã đề cập ngắn gọn:

Bạn có thể sử dụng Cgroup để hạn chế sử dụng tài nguyên và ngăn chặn các sự cố như vậy

Thật vậy, các nhóm cung cấp kiểm soát nâng cao hơn, nhưng hiện tại phức tạp hơn để cấu hình theo ý kiến ​​của tôi.

Trường học cũ

Sau khi tắt

Đây là một ví dụ đơn giản:

$ bash
$ ulimit -S -v $((1*2**20))
$ r2(){r2 $@$@;};r2 r2
bash: xmalloc: .././subst.c:3550: cannot allocate 134217729 bytes (946343936 bytes allocated)

Nó:

  • Đặt giới hạn mềm cho việc sử dụng bộ nhớ tổng thể 1GB (ulimit giả sử giới hạn tính theo đơn vị kB)
  • Chạy một lệnh gọi hàm bash đệ quy r2(){ r2 $@$@;};r2 r2sẽ nhai theo cấp số nhân CPU và RAM bằng cách nhân đôi vô hạn trong khi yêu cầu bộ nhớ ngăn xếp.

Như bạn có thể thấy, nó đã dừng lại khi cố gắng yêu cầu nhiều hơn 1GB.

Lưu ý, -vhoạt động dựa trên phân bổ bộ nhớ ảo (tổng, tức là vật lý + trao đổi).

Bảo vệ vĩnh viễn

Để hạn chế cấp phát bộ nhớ ảo, astương đương -vvới limits.conf.

Tôi làm như sau để bảo vệ chống lại bất kỳ quy trình xử lý sai nào:

  • Đặt giới hạn không gian địa chỉ cứng cho tất cả các quy trình.
  • address space limit = <physical memory> - 256MB.
  • Do đó, không có quá trình đơn lẻ nào sử dụng bộ nhớ tham lam hoặc vòng lặp hoạt động và rò rỉ bộ nhớ có thể tiêu thụ TẤT CẢ bộ nhớ vật lý.
  • Khoảng trống 256 MB là có để xử lý thiết yếu với ssh hoặc bàn điều khiển.

Lót:

$ sudo bash -c "echo -e \"*\thard\tas\t$(($(grep -E 'MemTotal' /proc/meminfo | grep -oP '(?<=\s)\d+(?=\skB$)') - 256*2**10))\" > /etc/security/limits.d/mem.conf"

Để xác thực, điều này dẫn đến kết quả sau (ví dụ: trên hệ thống 16 GB):

$ cat /etc/security/limits.d/mem.conf
*   hard    as      16135196
$ ulimit -H -v
161351960

Ghi chú:

  • Chỉ giảm nhẹ chống lại một quá trình duy nhất quá mức với việc sử dụng bộ nhớ.
  • Sẽ không ngăn chặn khối lượng công việc nhiều quy trình với áp lực bộ nhớ lớn gây ra sự cố (các nhóm sau đó là câu trả lời).
  • Đừng sử dụng rsstùy chọn trong giới hạn. Nó không được tôn trọng bởi các hạt nhân mới hơn.
  • Thật bảo thủ.
    • Về lý thuyết, một quy trình có thể yêu cầu rất nhiều bộ nhớ nhưng chỉ chủ động sử dụng một tập hợp con (sử dụng bộ làm việc / bộ nhớ lưu trú nhỏ hơn).
    • Giới hạn cứng ở trên sẽ khiến các quy trình đó bị hủy bỏ (ngay cả khi chúng có thể chạy tốt nếu không, Linux cho phép không gian địa chỉ bộ nhớ ảo bị quá tải).

Nhóm mới hơn

Cung cấp nhiều kiểm soát hơn, nhưng hiện tại phức tạp hơn để sử dụng:

  • Cải thiện về cung cấp ulimit.
    • memory.max_usage_in_bytes có thể tài khoản và giới hạn bộ nhớ vật lý riêng biệt.
    • Trong khi đó ulimit -mvà / hoặc rsstrong limits.confcó nghĩa là cung cấp chức năng tương tự, nhưng điều đó không hoạt động kể từ kernel Linux 2.4.30!
  • Cần kích hoạt một số cờ cgroup kernel trong bootloader : cgroup_enable=memory swapaccount=1.
    • Điều này đã không xảy ra theo mặc định với Ubuntu 16.04.
    • Có lẽ là do một số tác động hiệu suất của chi phí kế toán thêm.
  • công cụ cgroup / systemd tương đối mới và thay đổi một chút công bằng, do đó, dòng ngược dòng ngụ ý các nhà cung cấp phân phối Linux chưa làm cho nó dễ sử dụng. Từ 14.04LTS đến 16.04LTS, công cụ không gian người dùng để sử dụng các nhóm đã thay đổi.
    • cgm bây giờ dường như là công cụ không gian người dùng được hỗ trợ chính thức.
    • Các tệp đơn vị systemd dường như chưa có mặc định "nhà cung cấp / phân phối" được xác định trước để ưu tiên các dịch vụ quan trọng như ssh.

Ví dụ: để kiểm tra cài đặt hiện tại:

$ echo $(($(cat /sys/fs/cgroup/memory/memory.max_usage_in_bytes) / 2**20)) MB
11389 MB
$ cat /sys/fs/cgroup/memory/memory.stat
...

Ví dụ: để giới hạn bộ nhớ của một quá trình duy nhất:

$ cgm create memory mem_1G
$ cgm setvalue memory mem_1G memory.limit_in_bytes $((1*2**30))
$ cgm setvalue memory mem_1G memory.memsw.limit_in_bytes $((1*2**30))
$ bash
$ cgm movepid memory mem_1G $$
$ r2(){ r2 $@$@;};r2 r2
Killed

Để xem nó trong hành động nhai RAM như một quá trình nền và sau đó bị giết:

$ bash -c 'cgm movepid memory mem_1G $$; r2(){ r2 $@$@;};r2 r2' & while [ -e /proc/$! ]; do ps -p $! -o pcpu,pmem,rss h; sleep 1; done
[1] 3201
 0.0  0.0  2876
 102  0.2 44056
 103  0.5 85024
 103  1.0 166944
 ...
98.9  5.6 920552
99.1  4.3 718196
[1]+  Killed                  bash -c 'cgm movepid memory mem_1G $$; r2(){ r2 $@$@;};r2 r2'

Lưu ý sự tăng trưởng theo cấp số nhân (sức mạnh của 2) trong các yêu cầu bộ nhớ.

Trong tương lai, chúng ta hy vọng sẽ thấy "distro / nhà cung cấp" cấu hình trước các ưu tiên và giới hạn của nhóm (thông qua các đơn vị systemd) cho những thứ quan trọng như SSH và ngăn xếp đồ họa, để chúng không bao giờ bị bỏ đói bộ nhớ.


2

Bạn có thể nhấn Ctrl- zđể tạm dừng chương trình. Sau đó, bạn có thể làm kill %1(hoặc bất kể số công việc là gì hoặc bạn có thể sử dụng PID).

Bạn có thể sử dụng ulimitlệnh để cố gắng giới hạn dung lượng bộ nhớ có sẵn cho một tiến trình.


Ctrl-Z rất hay, nhưng thông thường tôi đang chạy GUI Matlab và bị mất dấu của thiết bị đầu cuối điều khiển, vì vậy không có cách nào dễ dàng để phát hành phím nhấn Ctrl-Z. Sẽ thật tuyệt nếu GUI có một phím nóng để gửi SIGSTOP đến bất kỳ ứng dụng nào có trọng tâm!
nibot

Bạn có thể chạy kill -STOP <pid>sẽ làm điều tương tự như Ctrl-Z.
hlovdal

Có, nhưng toàn bộ vấn đề là, trong tình huống như vậy, hệ thống không phản hồi đến mức phải mất một thời gian dài (hoặc mãi mãi) để đến dấu nhắc lệnh.
nibot

1

Bạn có thể sử dụng Cgroup để hạn chế sử dụng tài nguyên và ngăn chặn các sự cố như vậy: https://en.wikipedia.org/wiki/Cgroups


Vui lòng bao gồm các thông tin cần thiết trong câu trả lời của bạn và sử dụng liên kết chỉ để ghi nhận và đọc thêm. Liên kết đó mô tả Cgroup là gì, nhưng không rõ ràng từ liên kết làm thế nào để thực sự sử dụng nó để giải quyết vấn đề. Bạn có thể mở rộng câu trả lời của bạn để mô tả giải pháp cho câu hỏi không? Cảm ơn.
fixer1234

0

Sẽ thật tuyệt nếu GUI có một phím nóng để gửi SIGSTOP đến bất kỳ ứng dụng nào có trọng tâm!

Luôn có xkilllệnh cổ điển (từ xorg-x11-apps-7.4-14.fc14.src.rpm trên hệ thống của tôi). Tôi đoán không nên quá khó để tạo một bản sao gửi SIGSTOP thay vì giết cửa sổ mục tiêu.


Làm thế nào tôi có thể làm cho xkill khởi động nhanh chóng chỉ bằng cách nhấn một số tổ hợp phím?
nibot

Tôi không chắc. Tôi giả sử cả gnome và KDE đều có một số chức năng phím tắt toàn cầu có thể được sử dụng để khởi chạy chương trình.
hlovdal
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.