Linux จะเริ่มฆ่ากระบวนการของฉันโดยไม่ถามฉันหรือไม่ว่าหน่วยความจำสั้น


66

ฉันใช้เชลล์สคริปต์พร้อมคำสั่งเพื่อรันโปรแกรมที่ใช้หน่วยความจำมาก (2-5 GB) กลับไปด้านหลัง เมื่อฉันกลับไปตรวจสอบความคืบหน้าของสคริปต์ของฉันฉันรู้สึกประหลาดใจที่พบว่ากระบวนการบางอย่างของฉันเป็นKilledไปตามที่สถานีของฉันรายงานให้ฉัน มีหลายโปรแกรมที่ทำเสร็จแล้วอย่างต่อเนื่องก่อนที่โปรแกรมที่จะKilledเริ่มในภายหลังแต่โปรแกรมทั้งหมดหลังจากนั้นล้มเหลวในการแบ่งส่วนความผิดพลาด (ซึ่งอาจหรืออาจไม่ได้เกิดจากข้อผิดพลาดในรหัสของฉันอ่านต่อไป)

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

เป็นไปได้ไหมที่ลีนุกซ์ฆ่าโปรแกรมของฉันเมื่อหน่วยความจำไม่เพียงพอ? และเป็นไปได้ไหมที่การแบ่งส่วนที่ผิดพลาดที่ฉันได้รับในภายหลังนั้นเกิดจากการขาดหน่วยความจำที่พร้อมใช้งานเพื่อเรียกใช้โปรแกรมของฉัน (แทนที่จะเป็นจุดบกพร่องในรหัสของฉัน)?


2
เมื่อคุณจัดสรรหน่วยความจำคุณมีคำสั่งให้ตรวจสอบว่าจัดสรรหน่วยความจำสำเร็จหรือไม่? ที่ควรให้เบาะแสว่ามีข้อผิดพลาดในรหัสของคุณหรือไม่ว่าเป็นเพราะหน่วยความจำไม่เพียงพอในระบบ
unxnut

คำตอบ:


72

มันสามารถ

มีเงื่อนไขหน่วยความจำที่แตกต่างกันสองแบบที่คุณสามารถพบได้ใน Linux ซึ่งคุณพบขึ้นอยู่กับมูลค่าของsysctl vm.overcommit_memory( /proc/sys/vm/overcommit_memory)

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

overcommit_memory = 2

เมื่อovercommit_memoryตั้งค่า2เป็นเคอร์เนลจะไม่ทำการ overcommit ใด ๆ เลย แต่เมื่อโปรแกรมได้รับการจัดสรรหน่วยความจำจะเป็นการรับประกันว่าการเข้าถึงจะมีหน่วยความจำนั้น หากระบบไม่มีหน่วยความจำว่างเพียงพอที่จะตอบสนองการร้องขอการจัดสรรเคอร์เนลจะส่งคืนความล้มเหลวสำหรับการร้องขอ มันขึ้นอยู่กับโปรแกรมที่จะจัดการกับสถานการณ์อย่างสง่างาม หากไม่ได้ตรวจสอบว่าการจัดสรรสำเร็จเมื่อล้มเหลวจริง ๆ แอปพลิเคชันมักจะพบกับ segfault

ในกรณีของ segfault คุณควรหาบรรทัดเช่นนี้ในผลลัพธ์ของdmesg:

[1962.987529] myapp[3303]: segfault at 0 ip 00400559 sp 5bc7b1b0 error 6 in myapp[400000+1000]

at 0หมายความว่าโปรแกรมพยายามที่จะเข้าถึงตัวชี้เตรียมซึ่งอาจจะเป็นผลมาจากการเรียกร้องการจัดสรรหน่วยความจำที่ล้มเหลว ( แต่มันไม่ได้เป็นวิธีเดียว)

overcommit_memory = 0 และ 1

เมื่อovercommit_memoryตั้งค่าเป็น0หรือ1เปิดใช้งาน overcommit แล้วและโปรแกรมได้รับอนุญาตให้จัดสรรหน่วยความจำได้มากกว่าที่มีจริง ๆ

อย่างไรก็ตามเมื่อโปรแกรมต้องการใช้หน่วยความจำที่ได้รับการจัดสรร แต่เคอร์เนลพบว่าไม่มีหน่วยความจำเพียงพอที่จะทำให้เป็นจริงมันต้องได้หน่วยความจำกลับมา ก่อนอื่นจะพยายามดำเนินการงานล้างหน่วยความจำต่าง ๆ เช่นการล้างแคช แต่ถ้าไม่เพียงพอก็จะยุติกระบวนการ การยุตินี้ดำเนินการโดย OOM-Killer OOM-Killer ดูที่ระบบเพื่อดูว่าโปรแกรมใดบ้างที่ใช้หน่วยความจำระยะเวลาที่ใช้งานผู้ใช้งานและปัจจัยอื่น ๆ เพื่อพิจารณาว่าโปรแกรมใดถูกฆ่า

หลังจากกระบวนการถูกฆ่าหน่วยความจำที่ใช้อยู่นั้นถูกทำให้เป็นอิสระและโปรแกรมที่เพิ่งทำให้เกิดสภาวะหน่วยความจำไม่เพียงพอในตอนนี้มีหน่วยความจำที่ต้องการ

อย่างไรก็ตามแม้ในโหมดนี้โปรแกรมยังสามารถปฏิเสธคำขอการจัดสรรได้ เมื่อovercommit_memoryใด0เคอร์เนลจะพยายามคาดเดาได้ดีที่สุดว่าควรเริ่มปฏิเสธคำขอการจัดสรรเมื่อใด เมื่อตั้งค่าเป็น1ฉันไม่แน่ใจว่าจะใช้การกำหนดว่าควรปฏิเสธคำขอเมื่อใด แต่สามารถปฏิเสธคำขอที่มีขนาดใหญ่มากได้

คุณสามารถดูว่า OOM-Killer เกี่ยวข้องหรือไม่โดยดูจากผลลัพธ์dmesgและค้นหาข้อความเช่น:

[11686.043641] Out of memory: Kill process 2603 (flasherav) score 761 or sacrifice child
[11686.043647] Killed process 2603 (flasherav) total-vm:1498536kB, anon-rss:721784kB, file-rss:4228kB

ดังนั้นดูเหมือนว่าทั้งสองสถานการณ์เกิดขึ้นกับฉัน
NeutronStar

@ โจชัวฉันเพิ่งปรับปรุงคำตอบ ฉันลืมที่จะพูดถึงว่าคุณยังคงสามารถรับการจัดสรรล้มเหลวได้เมื่อovercommit_memoryตั้งค่าเป็น 0 หรือ 2
Patrick

ฉันคิดว่าการแก้ไขลิงก์ไปที่ทำให้เชื่อง OOM killerลงในโพสต์อาจคุ้มค่า
0xC0000022L

@ 0xC0000022L ขอบคุณนี่เป็นบทความที่ดี (แม้ว่าจะล้าสมัยไปเล็กน้อย) ฉันไม่ต้องการใส่อะไรในการควบคุมนักฆ่า OOM เพราะนั่นไม่ใช่ส่วนหนึ่งของคำถาม (และไม่ใช่เรื่องสั้น) และเรามีคำถามอื่นอีกมากมายที่นี่เกี่ยวกับเรื่องนี้
แพทริค

1
@mikeserv ฉันไม่ได้บอกว่าพฤติกรรมของนักฆ่า OOM ไม่มีส่วนเกี่ยวข้องกับการควบคุมมัน คำถามคือว่า linux จะฆ่าโปรแกรมของเขา วิธีการป้องกันไม่ให้ลินุกซ์ทำเช่นนั้นก่อนอื่นต้องมีการพิสูจน์ว่ามันคือลินุกซ์ และถ้าovercommit_memory=2นักฆ่า OOM ไม่ได้เปิดใช้งานดังนั้นการควบคุมมันจึงไม่เกี่ยวข้อง อย่างไรก็ตามเมื่อเราพิสูจน์ได้ว่ามันเป็นนักฆ่า OOM มันจะกลายเป็นอีกเรื่องหนึ่งที่ครอบคลุมคำถามและคำตอบอื่น ๆ อีกมากมายที่นี่
แพทริค

16

ความจริงก็คือไม่ว่าคุณจะมองด้วยวิธีใด - ไม่ว่ากระบวนการของคุณจะสำลักเนื่องจากผู้จัดการหน่วยความจำของระบบหรือเนื่องจากสิ่งอื่น - มันยังคงเป็นข้อผิดพลาด เกิดอะไรขึ้นกับข้อมูลทั้งหมดที่คุณเพิ่งประมวลผลในหน่วยความจำ ควรได้รับการบันทึก

แม้ว่าovercommit_memory=จะเป็นวิธีทั่วไปที่สุดในการกำหนดค่าการจัดการ Linux OOM แต่ก็สามารถปรับได้ตามกระบวนการเช่น:

echo [-+][n] >/proc/$pid/oom_adj

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

คุณสามารถตรวจสอบการตั้งค่าปัจจุบันของตัวจัดการ OOM ต่อกระบวนการเช่น:

cat /proc/$pid/oom_score 

มิฉะนั้นคุณสามารถฆ่าตัวตาย:

sysctl vm.panic_on_oom=1
sysctl kernel.panic=X

ที่จะตั้งค่าคอมพิวเตอร์ให้รีบูตในกรณีที่หน่วยความจำไม่เพียงพอ คุณตั้งค่าXข้างต้นเป็นจำนวนวินาทีที่คุณต้องการให้คอมพิวเตอร์หยุดหลังจากเคอร์เนลตกใจก่อนทำการรีบูต ไปป่า

และถ้าด้วยเหตุผลบางอย่างคุณตัดสินใจว่าคุณชอบทำให้เป็นแบบถาวร:

echo "vm.panic_on_oom=1" >> /etc/sysctl.conf
echo "kernel.panic=X" >> /etc/sysctl.conf

เป็นกลุ่มที่ใช้ร่วมกันที่ฉันใช้ฉันแน่ใจว่าผู้ใช้รายอื่นจะไม่ขอบคุณที่เริ่มต้นใหม่โดยไม่ได้รับความยินยอม
NeutronStar

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