กระบวนการย่อยของ Python เปิด“ OSError: [Errno 12] ไม่สามารถจัดสรรหน่วยความจำได้”


114

หมายเหตุ:คำถามนี้เดิมถูกถามที่นี่แต่เวลาของรางวัลหมดลงแม้ว่าจะไม่พบคำตอบที่ยอมรับได้ก็ตาม ฉันกำลังถามคำถามนี้อีกครั้งรวมถึงรายละเอียดทั้งหมดที่ให้ไว้ในคำถามเดิม

สคริปต์ python กำลังรันชุดฟังก์ชันคลาสทุกๆ 60 วินาทีโดยใช้โมดูลsched :

# sc is a sched.scheduler instance
sc.enter(60, 1, self.doChecks, (sc, False))

สคริปต์ที่ทำงานเป็นกระบวนการ daemonised โดยใช้รหัสที่นี่

เมธอดคลาสจำนวนหนึ่งที่เรียกว่าเป็นส่วนหนึ่งของ doChecks ใช้โมดูลกระบวนการย่อยเพื่อเรียกใช้ฟังก์ชันระบบเพื่อรับสถิติของระบบ:

ps = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE).communicate()[0]

สิ่งนี้ทำงานได้ดีในช่วงเวลาหนึ่งก่อนที่สคริปต์ทั้งหมดจะหยุดทำงานโดยมีข้อผิดพลาดต่อไปนี้:

File "/home/admin/sd-agent/checks.py", line 436, in getProcesses
File "/usr/lib/python2.4/subprocess.py", line 533, in __init__
File "/usr/lib/python2.4/subprocess.py", line 835, in _get_handles
OSError: [Errno 12] Cannot allocate memory

ผลลัพธ์ของ free -m บนเซิร์ฟเวอร์เมื่อสคริปต์ขัดข้องคือ:

$ free -m
                  total       used       free     shared     buffers    cached
Mem:                894        345        549          0          0          0
-/+ buffers/cache:  345        549
Swap:                 0          0          0

เซิร์ฟเวอร์กำลังเรียกใช้ CentOS 5.3 ฉันไม่สามารถทำซ้ำบนกล่อง CentOS ของตัวเองหรือกับผู้ใช้รายอื่นที่รายงานปัญหาเดียวกันนี้

ฉันได้ลองหลายสิ่งเพื่อแก้ไขข้อบกพร่องตามที่แนะนำในคำถามเดิม:

  1. บันทึกเอาต์พุตของ free -m ก่อนและหลังการโทร Popen ไม่มีการเปลี่ยนแปลงอย่างมีนัยสำคัญในการใช้หน่วยความจำกล่าวคือหน่วยความจำจะไม่ถูกใช้อย่างค่อยเป็นค่อยไปขณะที่สคริปต์ทำงาน

  2. ฉันเพิ่ม close_fds = True ให้กับการโทร Popen แต่สิ่งนี้ไม่ได้สร้างความแตกต่าง - สคริปต์ยังคงล้มเหลวด้วยข้อผิดพลาดเดียวกัน แนะนำที่นี่และที่นี่

  3. ฉันจะตรวจสอบ rlimits ซึ่งแสดงให้เห็น (-1, -1) ทั้ง RLIMIT_DATA และ RLIMIT_AS เป็นข้อเสนอแนะที่นี่

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

  5. กระบวนการที่ถูกปิดเพราะเห็นว่าเป็นพฤติกรรมของการใช้ .communicate () เช่นการสำรองข้อมูลโดยรหัสที่มาหลามและการแสดงความคิดเห็นที่นี่

ตรวจสอบทั้งหมดได้ที่GitHub ที่นี่ด้วยฟังก์ชัน getProcesses ที่กำหนดจากบรรทัด 442 ซึ่งเรียกโดย doChecks () เริ่มต้นที่บรรทัด 520

สคริปต์ถูกรันด้วย strace พร้อมเอาต์พุตต่อไปนี้ก่อนที่จะหยุดทำงาน:

recv(4, "Total Accesses: 516662\nTotal kBy"..., 234, 0) = 234
gettimeofday({1250893252, 887805}, NULL) = 0
write(3, "2009-08-21 17:20:52,887 - checks"..., 91) = 91
gettimeofday({1250893252, 888362}, NULL) = 0
write(3, "2009-08-21 17:20:52,888 - checks"..., 74) = 74
gettimeofday({1250893252, 888897}, NULL) = 0
write(3, "2009-08-21 17:20:52,888 - checks"..., 67) = 67
gettimeofday({1250893252, 889184}, NULL) = 0
write(3, "2009-08-21 17:20:52,889 - checks"..., 81) = 81
close(4)                                = 0
gettimeofday({1250893252, 889591}, NULL) = 0
write(3, "2009-08-21 17:20:52,889 - checks"..., 63) = 63
pipe([4, 5])                            = 0
pipe([6, 7])                            = 0
fcntl64(7, F_GETFD)                     = 0
fcntl64(7, F_SETFD, FD_CLOEXEC)         = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb7f12708) = -1 ENOMEM (Cannot allocate memory)
write(2, "Traceback (most recent call last"..., 35) = 35
open("/usr/bin/sd-agent/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/bin/sd-agent/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python24.zip/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/plat-linux2/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python2.4/lib-tk/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/lib-dynload/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/site-packages/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(2, "  File \"/usr/bin/sd-agent/agent."..., 52) = 52
open("/home/admin/sd-agent/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/bin/sd-agent/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python24.zip/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/plat-linux2/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python2.4/lib-tk/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/lib-dynload/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/site-packages/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(2, "  File \"/home/admin/sd-agent/dae"..., 60) = 60
open("/usr/bin/sd-agent/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/bin/sd-agent/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python24.zip/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/plat-linux2/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python2.4/lib-tk/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/lib-dynload/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/site-packages/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(2, "  File \"/usr/bin/sd-agent/agent."..., 54) = 54
open("/usr/lib/python2.4/sched.py", O_RDONLY|O_LARGEFILE) = 8
write(2, "  File \"/usr/lib/python2.4/sched"..., 55) = 55
fstat64(8, {st_mode=S_IFREG|0644, st_size=4054, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7d28000
read(8, "\"\"\"A generally useful event sche"..., 4096) = 4054
write(2, "    ", 4)                     = 4
write(2, "void = action(*argument)\n", 25) = 25
close(8)                                = 0
munmap(0xb7d28000, 4096)                = 0
open("/usr/bin/sd-agent/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/bin/sd-agent/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python24.zip/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/plat-linux2/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python2.4/lib-tk/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/lib-dynload/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/site-packages/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(2, "  File \"/usr/bin/sd-agent/checks"..., 60) = 60
open("/usr/bin/sd-agent/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/bin/sd-agent/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python24.zip/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/plat-linux2/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python2.4/lib-tk/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/lib-dynload/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/site-packages/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(2, "  File \"/usr/bin/sd-agent/checks"..., 64) = 64
open("/usr/lib/python2.4/subprocess.py", O_RDONLY|O_LARGEFILE) = 8
write(2, "  File \"/usr/lib/python2.4/subpr"..., 65) = 65
fstat64(8, {st_mode=S_IFREG|0644, st_size=39931, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7d28000
read(8, "# subprocess - Subprocesses with"..., 4096) = 4096
read(8, "lso, the newlines attribute of t"..., 4096) = 4096
read(8, "code < 0:\n        print >>sys.st"..., 4096) = 4096
read(8, "alse does not exist on 2.2.0\ntry"..., 4096) = 4096
read(8, " p2cread\n        # c2pread    <-"..., 4096) = 4096
write(2, "    ", 4)                     = 4
write(2, "errread, errwrite)\n", 19)    = 19
close(8)                                = 0
munmap(0xb7d28000, 4096)                = 0
open("/usr/lib/python2.4/subprocess.py", O_RDONLY|O_LARGEFILE) = 8
write(2, "  File \"/usr/lib/python2.4/subpr"..., 71) = 71
fstat64(8, {st_mode=S_IFREG|0644, st_size=39931, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7d28000
read(8, "# subprocess - Subprocesses with"..., 4096) = 4096
read(8, "lso, the newlines attribute of t"..., 4096) = 4096
read(8, "code < 0:\n        print >>sys.st"..., 4096) = 4096
read(8, "alse does not exist on 2.2.0\ntry"..., 4096) = 4096
read(8, " p2cread\n        # c2pread    <-"..., 4096) = 4096
read(8, "table(self, handle):\n           "..., 4096) = 4096
read(8, "rrno using _sys_errlist (or siml"..., 4096) = 4096
read(8, " p2cwrite = None, None\n         "..., 4096) = 4096
write(2, "    ", 4)                     = 4
write(2, "self.pid = os.fork()\n", 21)  = 21
close(8)                                = 0
munmap(0xb7d28000, 4096)                = 0
write(2, "OSError", 7)                  = 7
write(2, ": ", 2)                       = 2
write(2, "[Errno 12] Cannot allocate memor"..., 33) = 33
write(2, "\n", 1)                       = 1
unlink("/var/run/sd-agent.pid")         = 0
close(3)                                = 0
munmap(0xb7e0d000, 4096)                = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x589978}, {0xb89a60, [], SA_RESTORER, 0x589978}, 8) = 0
brk(0xa022000)                          = 0xa022000
exit_group(1)                           = ?

1
เรียกใช้ 'ไพพ์' หรือตัวถอดรหัสไฟล์หรือทรัพยากรเคอร์เนลที่เกี่ยวข้องกับสิ่งเหล่านี้หรือไม่
Blauohr

ตรวจสอบ/var/log/messagesหรือdmesgคำสั่ง
mark4o

ไม่มีสิ่งใดในบันทึกที่เกี่ยวข้องกับเรื่องนี้
davidmytton

คุณเคยได้รับวิธีแก้ปัญหานี้หรือไม่? ฉันมีอาการคล้ายกันมาก ฉันมีหน่วยความจำสำรองมากมาย แต่หลังจากเพิ่ม swap (เหมือนคำตอบบางคำที่คุณแนะนำ) ปัญหาก็จะหายไป แค่สงสัยว่าคุณพบอะไรในช่วงหลายเดือนระหว่างนั้นถึงตอนนี้ - ขอบคุณ!
dpb

ฉันกำลังประสบปัญหาเดียวกัน แต่ไม่มีวิธีแก้ปัญหาใด ๆ ?

คำตอบ:


89

ตามกฎทั่วไป (เช่นในวานิลลาเมล็ด) fork/ cloneความล้มเหลวกับการENOMEM เกิดขึ้นโดยเฉพาะเพราะทั้งความซื่อสัตย์ต่อพระเจ้าออกจากหน่วยความจำสภาพ ( dup_mm, dup_task_struct, alloc_pid, mpol_dup, mm_initฯลฯ บ่น) หรือเพราะsecurity_vm_enough_memory_mmล้มเหลวคุณในขณะที่การบังคับใช้นโยบาย overcommit

เริ่มต้นด้วยการตรวจสอบ vmsize ของกระบวนการที่ล้มเหลวในการแยกในขณะที่พยายามส้อมแล้วเปรียบเทียบกับจำนวนหน่วยความจำที่ว่าง (ฟิสิคัลและการสลับ) ตามที่เกี่ยวข้องกับนโยบาย overcommit (เสียบตัวเลขเข้า)

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

ตอนนี้เพื่อที่จะก้าวไปข้างหน้าฉันจะบอกว่าคุณมีสองทางเลือก :

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

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

เรารู้ดีอยู่แล้วว่าsubprocess.Popenใช้fork/ clone ภายใต้ประทุนซึ่งหมายความว่าทุกครั้งที่คุณเรียกมันคุณจะขอหน่วยความจำอีกครั้งเท่ากับที่ Python กินหมดแล้วนั่นคือในส่วนของ MB ที่เพิ่มขึ้นหลายร้อย MB ทั้งหมดตามลำดับexecปฏิบัติการ 10kB puny เช่นfreeหรือps. ในกรณีของนโยบาย overcommit ที่ไม่เอื้ออำนวยคุณจะพบในไม่ช้าENOMEMนี้จะเห็น

ทางเลือกในการforkที่ไม่ได้นี้ตารางเพจ ฯลฯ คัดลอกปัญหาเป็นและvfork posix_spawnแต่ถ้าคุณไม่รู้สึกอยากเขียนส่วนsubprocess.Popenในแง่ของvfork/ ใหม่posix_spawnให้พิจารณาใช้suprocess.Popenเพียงครั้งเดียวในตอนต้นของสคริปต์ของคุณ (เมื่อรอยเท้าหน่วยความจำของ Python มีน้อยที่สุด) เพื่อสร้างเชลล์สคริปต์ที่เรียกใช้free/ ps/ sleepและสิ่งอื่นใดใน a วนซ้ำขนานกับสคริปต์ของคุณ สำรวจเอาต์พุตของสคริปต์หรืออ่านพร้อมกันซึ่งอาจมาจากเธรดแยกต่างหากหากคุณมีสิ่งอื่นที่ต้องดูแลแบบอะซิงโครนัส - ทำข้อมูลของคุณใน Python แต่ปล่อยให้การฟอร์กไปยังกระบวนการรอง

อย่างไรก็ตามในกรณีเฉพาะของคุณคุณสามารถข้ามการเรียกpsและfreeทั้งหมดได้ ที่มีข้อมูลพร้อมที่จะให้คุณในหลามโดยตรงจากprocfsไม่ว่าคุณจะเลือกที่จะเข้าถึงมันเองหรือผ่านทางห้องสมุดที่มีอยู่และ / หรือแพคเกจ ถ้าpsและfreeถูกสาธารณูปโภคเดียวที่คุณกำลังวิ่งแล้วคุณสามารถทำไปด้วยความsubprocess.Popenสมบูรณ์

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


8
ฉันพบว่าการวิ่งgc.collect()ก่อนจะsubprocess.Popenช่วยในกรณีที่คนเก็บขยะไม่วิ่งมาสักพัก
letmaik

ฉันเขียน deamon เพื่อจัดการกลยุทธ์สคริปต์ตัวช่วย: github.com/SeanHayes/errand-boy ฉันใช้มันในการผลิตกับลูกค้ารายหนึ่งและปัญหา "ไม่สามารถจัดสรรหน่วยความจำ" ของเราก็หายไป
Seán Hayes

ฉันขอขอบคุณสำหรับการวินิจฉัยที่เรียบง่ายเช่นการติดตาม/proc/fd/mapsเพื่อตรวจสอบว่าหน่วยความจำ overcommitted เป็นปัญหาจริงหรือไม่
Dima Tisnek

18

เมื่อมองจากผลลัพธ์ของfree -mฉันดูเหมือนว่าคุณไม่มีหน่วยความจำ swap ที่พร้อมใช้งาน ฉันไม่แน่ใจว่าใน Linux สามารถใช้ swap ได้โดยอัตโนมัติตามความต้องการหรือไม่ แต่ฉันประสบปัญหาเดียวกันและไม่มีคำตอบใดที่ช่วยฉันได้จริง อย่างไรก็ตามการเพิ่มหน่วยความจำ swap บางส่วนได้แก้ไขปัญหาในกรณีของฉันดังนั้นเนื่องจากอาจช่วยให้ผู้อื่นประสบปัญหาเดียวกันฉันจึงโพสต์คำตอบเกี่ยวกับวิธีเพิ่มการแลกเปลี่ยน 1GB (บน Ubuntu 12.04 แต่ควรทำงานในลักษณะเดียวกันสำหรับการแจกแจงอื่น ๆ )

ก่อนอื่นคุณสามารถตรวจสอบว่ามีการเปิดใช้งานหน่วยความจำ swap หรือไม่

$sudo swapon -s

หากว่างเปล่าแสดงว่าคุณไม่ได้เปิดใช้งานการแลกเปลี่ยนใด ๆ ในการเพิ่มการแลกเปลี่ยน 1GB:

$sudo dd if=/dev/zero of=/swapfile bs=1024 count=1024k
$sudo mkswap /swapfile
$sudo swapon /swapfile

เพิ่มบรรทัดต่อไปนี้fstabเพื่อทำให้การแลกเปลี่ยนเป็นแบบถาวร

$sudo vim /etc/fstab

     /swapfile       none    swap    sw      0       0 

แหล่งที่มาและข้อมูลเพิ่มเติมสามารถพบได้ที่นี่


1
แก้ไขปัญหาเดียวกันหรือปัญหาอื่น ๆ ได้หรือไม่?
Dima Tisnek

สิ่งนี้ให้ฉันที่ CentOS 6.4 พบข้อผิดพลาดขณะติดตั้ง awstats ขอบคุณ
Ruslan Abuzant

แม้ว่าสิ่งนี้จะให้ฉันรันโค้ด แต่ก็ไม่ได้ช่วยแก้ปัญหาได้จริงซึ่งอาจอยู่ในไลบรารีที่ฉันใช้
philmaweb

1
คุณแก้ไขปัญหาของฉัน ขอบคุณ! +1
sscirrus

8

การแลกเปลี่ยนอาจไม่ใช่ปลาเฮอริ่งแดงที่แนะนำก่อนหน้านี้ กระบวนการ python นั้นใหญ่แค่ไหนก่อนหน้าไฟล์ENOMEM ?

ภายใต้เคอร์เนล 2.6 /proc/sys/vm/swappinessจะควบคุมว่าเคอร์เนลจะเปลี่ยนเป็นสว็อปอย่างจริงจังเพียงใดและovercommit*ไฟล์ว่าเคอร์เนลสามารถแบ่งหน่วยความจำได้มากและแม่นยำเพียงใดด้วยการกระพริบตาและพยักหน้า เช่นเดียวกับสถานะความสัมพันธ์ facebook ของคุณ, มันซับซ้อน

... แต่ swap สามารถใช้ได้ตามความต้องการ (ตามเว็บโฮสต์) ...

แต่ไม่เป็นไปตามผลลัพธ์ของfree(1)คำสั่งของคุณซึ่งแสดงว่าไม่มีพื้นที่สว็อปที่อินสแตนซ์เซิร์ฟเวอร์ของคุณรู้จัก ตอนนี้โฮสต์เว็บของคุณอาจรู้มากกว่าฉันเกี่ยวกับหัวข้อนี้อย่างแน่นอน แต่ระบบ RHEL / CentOS เสมือนที่ฉันเคยใช้ได้รายงานว่ามีการแลกเปลี่ยนสำหรับระบบปฏิบัติการของแขก

การปรับใช้Red Hat KB บทความ 15252 :

ระบบ Red Hat Enterprise Linux 5 จะทำงานได้ดีโดยไม่มีพื้นที่สว็อปเลยตราบใดที่ผลรวมของหน่วยความจำที่ไม่ระบุชื่อและหน่วยความจำที่ใช้ร่วมกันของระบบ V น้อยกว่าประมาณ 3/4 ของจำนวน RAM .... ระบบที่มี RAM 4GB หรือน้อยกว่า [แนะนำให้มี]พื้นที่แลกเปลี่ยนขั้นต่ำ 2GB

เปรียบเทียบ/proc/sys/vmการตั้งค่าของคุณกับการติดตั้ง CentOS 5.3 ธรรมดา เพิ่มไฟล์ swap วงล้อลงswappinessและดูว่าคุณมีชีวิตอยู่อีกต่อไปหรือไม่


วิธีที่ดีที่สุดในการตรวจสอบขนาดของกระบวนการ python คืออะไร? ปล?
davidmytton

สิ่งที่ชอบps -o user,pid,vsz="Mem(Kb)" -o cmd $PYTHON_PIDหรือด้านบน (1) ควรทำ
pilcrow

7

สำหรับการแก้ไขที่ง่ายคุณสามารถทำได้

echo 1 > /proc/sys/vm/overcommit_memory

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


1
ขอบคุณมาก! วิธีแก้ปัญหาที่ง่ายเช่นนี้คุณช่วยชีวิตฉันไว้)
igolkotek

5

ฉันยังคงสงสัยว่าลูกค้า / ผู้ใช้ของคุณมีโมดูลเคอร์เนลหรือไดรเวอร์ที่โหลดซึ่งรบกวนการclone()เรียกของระบบ (อาจจะมีการปรับปรุงความปลอดภัยที่คลุมเครือบางอย่างเช่น LIDS แต่คลุมเครือมากกว่านี้) หรือกำลังเติมโครงสร้างข้อมูลเคอร์เนลบางส่วนที่ จำเป็นสำหรับfork()/ clone()เพื่อดำเนินการ (ตารางกระบวนการ, ตารางเพจ, ตารางอธิบายไฟล์ ฯลฯ )

นี่คือส่วนที่เกี่ยวข้องของfork(2)หน้าคน:

ข้อผิดพลาด
       EAGAIN fork () ไม่สามารถจัดสรรหน่วยความจำเพียงพอที่จะคัดลอกตารางเพจของพาเรนต์และจัดสรรโครงสร้างงานสำหรับ
              เด็ก.

       EAGAIN ไม่สามารถสร้างกระบวนการใหม่ได้เนื่องจากพบขีด จำกัด ทรัพยากร RLIMIT_NPROC ของผู้โทร ถึง
              เกินขีด จำกัด นี้กระบวนการต้องมีความสามารถ CAP_SYS_ADMIN หรือ CAP_SYS_RESOURCE

       ENOMEM fork () ไม่สามารถจัดสรรโครงสร้างเคอร์เนลที่จำเป็นได้เนื่องจากหน่วยความจำแน่น

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

บรรทัดที่เกี่ยวข้องในของคุณstraceคือ:

clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb7f12708) = -1 ENOMEM (Cannot allocate memory)

... ฉันรู้ว่าคนอื่นพูดถึงความพร้อมในการแลกเปลี่ยนและหน่วยความจำ (และฉันขอแนะนำให้คุณตั้งค่าอย่างน้อยพาร์ติชัน swap ขนาดเล็กแดกดันแม้ว่าจะอยู่ในดิสก์ RAM ก็ตาม ... เส้นทางรหัสผ่านเคอร์เนล Linux เมื่อมี แม้เพียงเล็กน้อยของการแลกเปลี่ยนที่มีอยู่ก็มีการใช้งานอย่างครอบคลุมมากกว่า (เส้นทางการจัดการข้อยกเว้น) ซึ่งไม่มีการแลกเปลี่ยนเป็นศูนย์

อย่างไรก็ตามฉันสงสัยว่านี่ยังคงเป็นปลาเฮอริ่งแดง

ข้อเท็จจริงที่ว่าfreeกำลังรายงานหน่วยความจำ 0 (ZERO) ที่แคชและบัฟเฟอร์ใช้อยู่นั้นรบกวนมาก ฉันสงสัยว่าfreeผลลัพธ์ ... และอาจเป็นปัญหาแอปพลิเคชันของคุณที่นี่มีสาเหตุมาจากโมดูลเคอร์เนลที่เป็นกรรมสิทธิ์ซึ่งรบกวนการจัดสรรหน่วยความจำไม่ทางใดก็ทางหนึ่ง

ตามหน้าคนสำหรับ fork () / clone () การเรียกระบบ fork () ควรส่งคืน EAGAIN หากการโทรของคุณทำให้เกิดการละเมิดขีด ​​จำกัด ทรัพยากร (RLIMIT_NPROC) ... อย่างไรก็ตามมันไม่ได้บอกว่าจะคืน EAGAIN หรือไม่ โดยการละเมิด RLIMIT * อื่น ๆ ไม่ว่าในกรณีใดก็ตามหากเป้าหมาย / โฮสต์ของคุณมีการตั้งค่า Vormetric แปลก ๆ หรือการตั้งค่าความปลอดภัยอื่น ๆ (หรือแม้ว่ากระบวนการของคุณกำลังทำงานภายใต้นโยบาย SELinux แปลก ๆ ) ก็อาจทำให้ -ENOMEM ล้มเหลวได้

ค่อนข้างไม่น่าจะเป็นปัญหา Linux / UNIX แบบรันปกติ คุณมีบางอย่างที่ไม่ได้มาตรฐานเกิดขึ้นที่นั่น


1
เซิร์ฟเวอร์กำลังรันบนฐาน Media Template (dv) ซึ่งใช้ Virtuozzo สำหรับ virtualisation
davidmytton

ลองค้นหากระดานข้อความ Virtuozzo และระบบติดตามข้อผิดพลาดและอาจมองหาการอัปเกรดระบบย่อย Virtuozzo เอง
Jim Dennis

2

คุณได้ลองใช้:

(status,output) = commands.getstatusoutput("ps aux")

ฉันคิดว่านี่ได้แก้ไขปัญหาเดียวกันสำหรับฉันแล้ว แต่แล้วกระบวนการของฉันก็จบลงด้วยการถูกฆ่าแทนที่จะเกิดไม่สำเร็จซึ่งเลวร้ายยิ่งกว่า ..

หลังจากการทดสอบบางครั้งฉันพบว่าสิ่งนี้เกิดขึ้นกับ python เวอร์ชันเก่าเท่านั้นมันเกิดขึ้นกับ 2.6.5 แต่ไม่ใช่กับ 2.7.2

การค้นหาของฉันทำให้ฉันมาที่นี่python-close_fds-issueแต่การยกเลิกการตั้งค่า closed_fds ไม่สามารถแก้ปัญหาได้ มันยังคงคุ้มค่าที่จะอ่าน

ฉันพบว่า python รั่วตัวอธิบายไฟล์โดยจับตาดูมัน:

watch "ls /proc/$PYTHONPID/fd | wc -l"

เช่นเดียวกับคุณฉันต้องการจับเอาท์พุทของคำสั่งและฉันต้องการหลีกเลี่ยงข้อผิดพลาด OOM ... ไม่เหมาะ ...


0

munmap (0xb7d28000, 4096) = 0
เขียน (2, "OSError", 7) = 7

ฉันเคยเห็นโค้ดเลอะเทอะที่มีลักษณะดังนี้:

serrno = errno;
some_Syscall(...)
if (serrno != errno)
/* sound alarm: CATROSTOPHIC ERROR !!! */

คุณควรตรวจสอบเพื่อดูว่านี่คือสิ่งที่เกิดขึ้นในรหัส python หรือไม่ Errno ใช้ได้เฉพาะในกรณีที่การเรียกระบบดำเนินการล้มเหลว

แก้ไขเพื่อเพิ่ม:

คุณไม่ได้บอกว่ากระบวนการนี้มีชีวิตอยู่นานแค่ไหน ผู้บริโภคที่เป็นไปได้ของหน่วยความจำ

  • กระบวนการแยก
  • โครงสร้างข้อมูลที่ไม่ได้ใช้
  • ไลบรารีที่ใช้ร่วมกัน
  • ไฟล์ที่แมปหน่วยความจำ

2
ใช่ แต่เราเห็นจาก strace ของ OP ว่าความล้มเหลวของ syscall ครั้งแรก - จาก clone () - เป็น ENOMEM ตามที่รายงาน ข้อผิดพลาดนี้จะถูกเก็บรักษาไว้พร้อมกับหน่วยความจำต่ำของ python สะดุดผ่านการสร้างย้อนกลับแม้ว่าไลบรารี C errnoจะถูกรีเซ็ตหลายครั้งระหว่างทาง
pilcrow

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