ฉันจะหยุดกระบวนการที่ทำให้เกิด thrashing อย่างรวดเร็วได้อย่างไร (เนื่องจากการจัดสรรหน่วยความจำส่วนเกิน)


19

เราได้รับประสบการณ์ทั้งหมด - บางโปรแกรมได้รับการขอให้ทำบางสิ่งที่ต้องใช้หน่วยความจำจำนวนมาก มันจะพยายามจัดสรรหน่วยความจำทั้งหมดนี้โดยอัตโนมัติและระบบจะเริ่มการฟาดฟันสลับอย่างไม่มีที่สิ้นสุดและกลายเป็นเฉื่อยชาหรือไม่ตอบสนอง

ฉันเพิ่งพบสิ่งนี้บนแล็ปท็อป Ubuntu ของฉันเนื่องจากสคริปต์ Matlab พยายามจัดสรรเมทริกซ์ขนาดใหญ่ที่น่าขัน หลังจากที่เฆี่ยนตีประมาณ 5 นาทีฉันก็สามารถ Ctrl-F1 ไปที่คอนโซลและฆ่า Matlab ฉันอยากจะมีคีย์ลัดซึ่งจะทำให้ฉันสามารถควบคุมระบบได้ทันทีและอนุญาตให้ฉันฆ่ากระบวนการที่ละเมิด หรือบางทีอาจปฏิเสธการจัดสรรบัฟเฟอร์ขนาดใหญ่แบบเงียบ ๆ

  1. อะไรคือวิธีที่เร็วที่สุดในการควบคุมระบบลีนุกซ์ที่ไม่ตอบสนองหรือซบเซาอย่างรุนแรงเนื่องจากการแลกเปลี่ยนมากเกินไป?

  2. มีวิธีที่มีประสิทธิภาพในการป้องกันการสลับที่เกิดขึ้นตั้งแต่แรกเช่นโดย จำกัด จำนวนหน่วยความจำที่กระบวนการอนุญาตให้ลองจัดสรรได้หรือไม่?

คำตอบ:


12

กดAlt-SysRq-Fเพื่อฆ่ากระบวนการโดยใช้หน่วยความจำส่วนใหญ่:

  • โดยปกติแล้วคีย์ SysRq จะถูกแมปกับแป้นพิมพ์
  • หากคุณใช้เดสก์ท็อปกราฟิกคุณอาจต้องกดCtrl-Alt-SysRq-Fในกรณีที่กดAlt-SysRqจะทำให้เกิดการกระทำอื่น (เช่นโปรแกรม snapshot)
  • หากคุณใช้แล็ปท็อปคุณอาจต้องกดปุ่มฟังก์ชั่นด้วย
  • สำหรับข้อมูลเพิ่มเติมอ่านบทความวิกิพีเดีย

5

ฉันได้สร้างสคริปต์เพื่อจุดประสงค์นี้ - https://github.com/tobixen/thrash-protect

ฉันเคยใช้สคริปต์นี้ทำงานบนเซิร์ฟเวอร์ที่ใช้งานจริงเวิร์กสเตชันและแล็ปท็อปที่ประสบความสำเร็จ สคริปต์นี้ไม่ได้ฆ่ากระบวนการ แต่หยุดชั่วคราวชั่วคราว - ฉันมีหลายสถานการณ์ในภายหลังที่ฉันค่อนข้างแน่ใจว่าฉันสูญเสียการควบคุมเนื่องจากการฟาดถ้ามันไม่ใช่สคริปต์ง่าย ๆ นี้ ในกรณีที่ "แย่ที่สุด" กระบวนการที่กระทำผิดกฎหมายจะช้าลงมากและในท้ายที่สุดจะถูกฆ่าโดยเคอร์เนล (OOM) ในกรณีที่ "ดีที่สุด" กระบวนการละเมิดจะเสร็จสมบูรณ์จริง ๆ ... ในกรณีใด ๆ เซิร์ฟเวอร์หรือเวิร์กสเตชัน จะยังค่อนข้างตอบสนองเพื่อให้ง่ายต่อการตรวจสอบสถานการณ์

แน่นอนว่า "ซื้อหน่วยความจำมากขึ้น" หรือ "ไม่ใช้ swap" เป็นสองทางเลือกคำตอบแบบดั้งเดิมสำหรับคำถามที่ว่า "จะหลีกเลี่ยงการฟาดฟันแบบไหน" แต่โดยทั่วไปแล้วพวกเขามักจะไม่ได้ผลดี ไม่โกงกระบวนการอันธพาลสามารถกินหน่วยความจำทั้งหมดไม่ว่าจะมีการติดตั้งมากแค่ไหนและสามารถแก้ปัญหาการฟาดฟันได้โดยไม่ต้องสลับเมื่อหน่วยความจำไม่เพียงพอสำหรับการบัฟเฟอร์ / แคช) ฉันแนะนำให้ใช้ thrash ป้องกันพร้อมกับพื้นที่สว็อปจำนวนมาก


เกี่ยวกับการปิดการใช้งาน swap ตามunix.stackexchange.com/a/24646/9108อาจเป็นตัวเลือกที่ดีที่สุด
sashoalm

อันที่จริงมีคนแสดงความคิดเห็นแบบเดียวกันกับฉันดังนั้นฉันจึงแก้ไขเอกสารป้องกันการตี ณ เวลานั้น
tobixen

4
  1. อะไรคือวิธีที่เร็วที่สุดในการควบคุมระบบลีนุกซ์ที่ไม่ตอบสนองหรือซบเซาอย่างรุนแรงเนื่องจากการแลกเปลี่ยนมากเกินไป?

ตอบไปแล้วข้างต้นด้วยAlt-SysRq-F

  1. มีวิธีที่มีประสิทธิภาพในการป้องกันการสลับที่เกิดขึ้นตั้งแต่แรกเช่นโดย จำกัด จำนวนหน่วยความจำที่กระบวนการอนุญาตให้ลองจัดสรรได้หรือไม่?

ฉันกำลังตอบส่วนที่ 2 นี้ ใช่ulimitยังทำงานได้ดีพอที่จะ จำกัด กระบวนการเดียว คุณสามารถ:

  • ตั้งค่าขีด จำกัด นุ่มนวลสำหรับกระบวนการที่คุณรู้ว่ามีแนวโน้มว่าจะอยู่นอกเหนือการควบคุม
  • กำหนดวงเงินที่เข้มงวดสำหรับกระบวนการทั้งหมดหากคุณต้องการประกันเพิ่มเติม

นอกจากนี้ตามที่กล่าวไว้สั้น ๆ :

คุณสามารถใช้กลุ่มเพื่อ จำกัด การใช้ทรัพยากรและป้องกันปัญหาดังกล่าว

แน่นอนกลุ่ม cg ให้การควบคุมขั้นสูงมากขึ้น แต่ในปัจจุบันมีความซับซ้อนในการกำหนดค่าในความคิดของฉัน

ulimit โรงเรียนเก่า

ทันทีที่ปิด

นี่เป็นตัวอย่างง่ายๆ:

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

มัน:

  • ตั้งค่าขีด จำกัด ซอฟต์ของการใช้หน่วยความจำโดยรวม 1GB (ulimit ถือว่า จำกัด เป็นหน่วย kB)
  • รันการเรียกใช้ฟังก์ชัน bash แบบเรียกซ้ำr2(){ r2 $@$@;};r2 r2ซึ่งจะทำการเคี้ยวซีพียูและ RAM อย่างทวีคูณโดยทวีคูณตัวมันเองเป็นสองเท่าในขณะที่ร้องขอหน่วยความจำสแต็ก

อย่างที่คุณเห็นมันหยุดเมื่อพยายามร้องขอมากกว่า 1GB

หมายเหตุ-vทำงานบนการจัดสรรหน่วยความจำเสมือน (ผลรวมคือการแลกเปลี่ยนทางกายภาพ +)

ป้องกันถาวร

เพื่อ จำกัด การจัดสรรหน่วยความจำเสมือนasเป็นเทียบเท่าของสำหรับ-vlimits.conf

ฉันทำสิ่งต่อไปนี้เพื่อป้องกันกระบวนการที่ทำงานผิดปกติใด ๆ :

  • ตั้งค่าขีด จำกัด พื้นที่แอดเดรสฮาร์ดสำหรับกระบวนการทั้งหมด
  • address space limit = <physical memory> - 256MB.
  • ดังนั้นไม่มีกระบวนการเดียวที่มีการใช้หน่วยความจำโลภหรือลูปที่ใช้งานอยู่และการรั่วไหลของหน่วยความจำสามารถใช้หน่วยความจำกายภาพทั้งหมด
  • headroom ขนาด 256MB สำหรับการประมวลผลที่จำเป็นด้วย ssh หรือคอนโซล

หนึ่งในสายการบิน:

$ 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"

ในการตรวจสอบความถูกต้องนี้จะส่งผลต่อไปนี้ (เช่นในระบบ 16GB):

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

หมายเหตุ:

  • ลดผลกระทบต่อกระบวนการเดียวที่ลงน้ำด้วยการใช้หน่วยความจำ
  • จะไม่ป้องกันภาระงานหลายกระบวนการด้วยแรงกดดันหน่วยความจำหนักทำให้เกิดการฟาดฟัน (กลุ่มคำตอบคือคำตอบ)
  • อย่าใช้rssตัวเลือกใน limit.conf มันไม่ได้เป็นที่เคารพนับถือของเมล็ดพันธุ์ใหม่
  • มันอนุรักษ์นิยม
    • ในทางทฤษฎีกระบวนการสามารถร้องขอหน่วยความจำจำนวนมากได้ แต่ใช้ชุดย่อยเท่านั้น (ใช้ชุดการทำงาน / การใช้หน่วยความจำขนาดเล็ก)
    • ขีด จำกัด ฮาร์ดด้านบนจะทำให้กระบวนการดังกล่าวหยุดทำงาน (แม้ว่าพวกเขาอาจทำงานได้ดีเนื่องจาก Linux อนุญาตให้ใช้พื้นที่ที่อยู่หน่วยความจำเสมือนมากเกินไป)

ใหม่กว่ากลุ่ม CG

ให้การควบคุมที่มากขึ้น แต่ในปัจจุบันมีความซับซ้อนในการใช้:

  • ปรับปรุงการเสนอ ulimit
    • memory.max_usage_in_bytes สามารถบัญชีและ จำกัด หน่วยความจำทางกายภาพแยกจากกัน
    • ในขณะที่ulimit -mและ / หรือrssในlimits.confหมายถึงการให้ฟังก์ชั่นที่คล้ายกัน แต่ไม่ได้ทำงานตั้งแต่ kernel Linux 2.4.30!
  • ต้องเปิดใช้งานธงเคอร์เนล cgroup บางอย่างใน cgroup_enable=memory swapaccount=1bootloader:
    • สิ่งนี้ไม่ได้เกิดขึ้นตามค่าเริ่มต้นกับ Ubuntu 16.04
    • อาจเป็นเพราะความเกี่ยวเนื่องของประสิทธิภาพของค่าใช้จ่ายทางบัญชีเพิ่มเติม
  • สิ่งที่ cgroup / systemd ค่อนข้างใหม่และการเปลี่ยนบิตที่เป็นธรรมดังนั้นฟลักซ์อัพสตรีมจึงสื่อถึงผู้จำหน่าย distro Linux ที่ยังไม่ได้ใช้งานง่าย ระหว่าง 14.04LTS ถึง 16.04LTS เครื่องมือพื้นที่ผู้ใช้ในการใช้กลุ่ม cg ได้เปลี่ยนไป
    • cgm ตอนนี้ดูเหมือนว่าจะเป็นเครื่องมือ userspace ที่สนับสนุนอย่างเป็นทางการ
    • ดูเหมือนว่าไฟล์หน่วย systemd ยังไม่มีค่าเริ่มต้น "ผู้จำหน่าย / distro" ที่กำหนดไว้ล่วงหน้าใด ๆ เพื่อจัดลำดับความสำคัญของบริการที่สำคัญเช่น ssh

เช่นเพื่อตรวจสอบการตั้งค่าปัจจุบัน:

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

เช่นเพื่อ จำกัด หน่วยความจำของกระบวนการเดียว:

$ 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

หากต้องการดูการใช้งานในการเคี้ยว RAM เป็นกระบวนการพื้นหลังแล้วถูกฆ่า:

$ 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'

สังเกตการเติบโตแบบเอ็กซ์โพเนนเชียล (กำลัง 2) ในคำขอหน่วยความจำ

ในอนาคตเราหวังว่าจะเห็น "distro / ผู้ขาย" กำหนดค่าลำดับความสำคัญและข้อ จำกัด ของ cgroup ล่วงหน้า (ผ่าน systemd units) สำหรับสิ่งที่สำคัญเช่น SSH และกราฟิกสแต็ก


2

คุณอาจสามารถกดCtrl- zเพื่อหยุดโปรแกรมชั่วคราว จากนั้นคุณสามารถทำได้kill %1(หรือหมายเลขงานใดก็ได้หรือคุณสามารถใช้ PID)

คุณสามารถใช้ulimitคำสั่งเพื่อพยายาม จำกัด จำนวนหน่วยความจำที่สามารถใช้ได้กับกระบวนการ


Ctrl-Z เป็นสิ่งที่ดี แต่ฉันมักจะใช้ Matlab GUI และสูญเสียการติดตามเทอร์มินัลการควบคุมดังนั้นจึงไม่มีวิธีที่ง่ายในการออกกดปุ่ม Ctrl-Z คงจะดีถ้า GUI มีฮอตคีย์เพื่อส่ง SIGSTOP ไปยังแอปพลิเคชันใดก็ตามที่มีโฟกัส!
nibot

คุณสามารถเรียกใช้kill -STOP <pid>ซึ่งจะทำเช่นเดียวกับ Ctrl-Z
hlovdal

ใช่ แต่ปัญหาทั้งหมดคือว่าในสถานการณ์เช่นนี้ระบบจะไม่ตอบสนองที่ใช้เวลานาน (หรือตลอดไป) เพื่อไปที่พร้อมรับคำสั่ง
nibot

1

คุณสามารถใช้กลุ่มเพื่อ จำกัด การใช้ทรัพยากรและป้องกันปัญหาดังกล่าว: https://en.wikipedia.org/wiki/Cgroups


โปรดระบุข้อมูลที่จำเป็นในคำตอบของคุณและใช้ลิงก์เพื่อระบุแหล่งที่มาและการอ่านเพิ่มเติม ลิงค์นั้นอธิบายว่ากลุ่ม CGGL คืออะไร แต่ไม่ชัดเจนจากลิงก์ถึงวิธีใช้งานจริงเพื่อแก้ไขปัญหา คุณสามารถขยายคำตอบเพื่ออธิบายการแก้ปัญหาให้กับคำถามได้หรือไม่? ขอบคุณ
fixer1234

0

คงจะดีถ้า GUI มีฮอตคีย์เพื่อส่ง SIGSTOP ไปยังแอปพลิเคชันใดก็ตามที่มีโฟกัส!

มีxkillคำสั่งคลาสสิกเสมอ(จาก xorg-x11-apps-7.4-14.fc14.src.rpm ในระบบของฉัน) ฉันเดาว่ามันไม่ควรจะยากเกินไปที่จะสร้างโคลนนิ่งที่ส่ง SIGSTOP แทนที่จะฆ่าหน้าต่างเป้าหมาย


ฉันจะทำให้ xkill เริ่มทำงานได้อย่างรวดเร็วด้วยการกดปุ่มผสมบางปุ่มได้อย่างไร
nibot

ฉันไม่แน่ใจ. ฉันถือว่าทั้ง gnome และ KDE มีฟังก์ชั่นทางลัดระดับโลกที่สามารถใช้ในการเปิดโปรแกรม
hlovdal
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.