Quy trình con Python. Mở “OSError: [Errno 12] Không thể cấp phát bộ nhớ”


114

Lưu ý: Câu hỏi này ban đầu được hỏi ở đây nhưng thời gian tiền thưởng đã hết hạn mặc dù không thực sự tìm thấy câu trả lời chấp nhận được. Tôi đang hỏi lại câu hỏi này bao gồm tất cả các chi tiết được cung cấp trong câu hỏi ban đầu.

Một tập lệnh python đang chạy một tập hợp các hàm lớp sau mỗi 60 giây bằng cách sử dụng mô-đun lập lịch :

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

Tập lệnh đang chạy như một quá trình được daemonised bằng cách sử dụng mã ở đây .

Một số phương thức lớp được gọi là một phần của doChecks sử dụng mô-đun quy trình con để gọi các chức năng hệ thống nhằm nhận thống kê hệ thống:

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

Điều này chạy tốt trong một khoảng thời gian trước khi toàn bộ tập lệnh bị lỗi với lỗi sau:

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

Đầu ra của -m miễn phí trên máy chủ sau khi tập lệnh gặp sự cố là:

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

Máy chủ đang chạy CentOS 5.3. Tôi không thể sao chép trên hộp CentOS của riêng mình cũng như với bất kỳ người dùng nào khác báo cáo vấn đề tương tự.

Tôi đã thử một số cách để gỡ lỗi điều này như được đề xuất trong câu hỏi ban đầu:

  1. Ghi nhật ký đầu ra của -m miễn phí trước và sau cuộc gọi Popen. Không có thay đổi đáng kể trong việc sử dụng bộ nhớ, tức là bộ nhớ không dần dần được sử dụng hết khi tập lệnh chạy.

  2. Tôi đã thêm close_fds = Đúng vào lệnh gọi Popen nhưng điều này không có gì khác biệt - tập lệnh vẫn bị lỗi với cùng một lỗi. Đề xuất ở đâyở đây .

  3. Tôi đã kiểm tra rlimits hiển thị (-1, -1) trên cả RLIMIT_DATA và RLIMIT_AS như được đề xuất ở đây .

  4. Một bài báo cho rằng không có không gian hoán đổi có thể là nguyên nhân nhưng hoán đổi thực sự có sẵn theo yêu cầu (theo máy chủ web) và điều này cũng được đề xuất là một nguyên nhân không có thật ở đây .

  5. Các quy trình đang bị đóng vì đó là hành vi sử dụng .communicate () được sao lưu bởi mã nguồn Python và nhận xét ở đây .

Toàn bộ quá trình kiểm tra có thể được tìm thấy trên GitHub ở đây với hàm getProcesses được xác định từ dòng 442. Điều này được gọi bởi doChecks () bắt đầu từ dòng 520.

Tập lệnh đã được chạy với strace với đầu ra sau đây trước khi gặp sự cố:

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
hết 'đường ống' hoặc bộ chỉ định tệp hoặc tài nguyên hạt nhân liên quan đến những thứ này?
Blauohr 02/09/09

Kiểm tra /var/log/messageshoặc ra dmesglệnh.
mark4o 02/09/09

Không có gì trong nhật ký liên quan đến điều này.
davidmytton

Bạn đã bao giờ nhận được một giải pháp cho điều này? Tôi có các triệu chứng rất giống nhau. Tôi có nhiều bộ nhớ dự phòng, nhưng sau khi thêm hoán đổi (như một số câu trả lời của bạn đề xuất), sự cố sẽ biến mất. Chỉ tự hỏi liệu bạn có phát hiện ra điều gì trong những tháng từ đó đến nay không. -- cảm ơn!
dpb

Tôi đang gặp phải vấn đề tương tự nhưng không có giải pháp - bất kỳ ý tưởng nào?

Câu trả lời:


88

Theo nguyên tắc chung (ví dụ trong vanilla kernel), fork/ clonethất bại với ENOMEM xảy ra đặc biệt vì cả hai một cách trung thực với Thiên Chúa out-of-bộ nhớ trạng thái ( dup_mm, dup_task_struct, alloc_pid, mpol_dup, mm_init, vv croak), hoặc vì security_vm_enough_memory_mmthất bại bạn trong khi thực thi các chính sách overcommit .

Bắt đầu bằng cách kiểm tra vmsize của quá trình không phân nhánh được, tại thời điểm cố gắng phân nhánh, sau đó so sánh với dung lượng bộ nhớ trống (vật lý và hoán đổi) vì nó liên quan đến chính sách gửi thừa (cắm số vào.)

Trong trường hợp cụ thể của bạn, hãy lưu ý rằng Virtuozzo có các kiểm tra bổ sung trong việc thực thi vượt cấp . Hơn nữa, tôi không chắc bạn thực sự có bao nhiêu quyền kiểm soát, từ bên trong vùng chứa của mình, cấu hình hoán đổi và gửi quá mức (để ảnh hưởng đến kết quả của việc thực thi).

Bây giờ, để thực sự tiến về phía trước, tôi muốn nói rằng bạn còn hai lựa chọn :

  • chuyển sang một phiên bản lớn hơn hoặc
  • đặt một số nỗ lực mã hóa vào việc kiểm soát hiệu quả hơn bộ nhớ tập lệnh của bạn dấu chân

LƯU Ý rằng nỗ lực mã hóa có thể vô ích nếu hóa ra không phải bạn mà là một người khác được sắp xếp trong một trường hợp khác trên cùng một máy chủ khi bạn đang chạy amock.

Memory-khôn ngoan, chúng tôi đã biết rằng subprocess.Popensử dụng fork/ clone dưới mui xe , có nghĩa là mỗi khi bạn gọi nó là bạn đang yêu cầu một lần nữa như bộ nhớ nhiều như Python đã được ăn lên , tức là trong hàng trăm MB bổ sung, tất cả để sau đó execmột tệp thực thi 10kB nhỏ bé chẳng hạn như freehoặc ps. Trong trường hợp chính sách vượt quá bất lợi, bạn sẽ sớm thấy ENOMEM.

Các giải pháp thay thế forkkhông có bảng trang mẹ này, vv vấn đề sao chép là vforkposix_spawn. Nhưng nếu bạn không cảm thấy muốn viết lại các đoạn subprocess.Popenvề vfork/ posix_spawn, hãy xem xét sử dụng suprocess.Popenchỉ một lần, ở đầu tập lệnh của bạn (khi bộ nhớ của Python là tối thiểu), để tạo ra một tập lệnh shell sau đó chạy free/ ps/ sleepvà bất kỳ thứ gì khác trong một lặp song song với tập lệnh của bạn; thăm dò kết quả đầu ra của tập lệnh hoặc đọc nó một cách đồng bộ, có thể từ một chuỗi riêng biệt nếu bạn có những thứ khác cần xử lý không đồng bộ - thực hiện xử lý dữ liệu của bạn bằng Python nhưng để lại sự phân tách cho quy trình cấp dưới.

TUY NHIÊN , trong trường hợp cụ thể của bạn, bạn có thể bỏ qua việc gọi psfreehoàn toàn; thông tinprocfs đó có sẵn cho bạn trực tiếp bằng Python , cho dù bạn chọn tự mình truy cập hay thông qua các thư viện và / hoặc gói hiện có . Nếu psfreelà tiện ích duy nhất bạn đang chạy, thì bạn có thể loại bỏ subprocess.Popenhoàn toàn .

Cuối cùng, bất cứ điều gì bạn làm trong chừng mực subprocess.Popencó liên quan, nếu tập lệnh của bạn bị rò rỉ bộ nhớ, cuối cùng bạn vẫn sẽ gặp nguy hiểm. Theo dõi và kiểm tra bộ nhớ bị rò rỉ .


7
Tôi thấy rằng việc chạy gc.collect()ngay trước đó subprocess.Popensẽ giúp ích trong trường hợp bộ thu gom rác đã không chạy trong một thời gian.
letmaik

Tôi đã viết một bản dừng để xử lý chiến lược tập lệnh trợ giúp: github.com/SeanHayes/errand-boy Tôi đang sử dụng nó trong sản xuất với một trong những khách hàng của mình và sự cố "Không thể cấp phát bộ nhớ" của chúng tôi đã biến mất.
Seán Hayes

Tôi đánh giá cao một chẩn đoán đơn giản, ví dụ như sau /proc/fd/mapsđể xác định xem bộ nhớ được truyền quá mức có thực sự là vấn đề hay không
Dima Tisnek

18

Nhìn vào đầu ra của free -mnó, tôi thấy rằng bạn thực sự không có sẵn bộ nhớ hoán đổi. Tôi không chắc liệu trong Linux có tính năng hoán đổi luôn tự động theo yêu cầu hay không, nhưng tôi đã gặp vấn đề tương tự và không có câu trả lời nào ở đây thực sự giúp được tôi. Tuy nhiên, việc thêm một số bộ nhớ hoán đổi, đã khắc phục sự cố trong trường hợp của tôi, vì điều này có thể giúp những người khác gặp phải vấn đề tương tự, tôi đăng câu trả lời của mình về cách thêm bộ nhớ hoán đổi 1GB (trên Ubuntu 12.04 nhưng nó sẽ hoạt động tương tự đối với các bản phân phối khác.)

Trước tiên, bạn có thể kiểm tra xem có bất kỳ bộ nhớ hoán đổi nào được bật không.

$sudo swapon -s

nếu nó trống, điều đó có nghĩa là bạn chưa bật bất kỳ hoán đổi nào. Để thêm 1 GB hoán đổi:

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

Thêm dòng sau vào fstabđể thực hiện hoán đổi vĩnh viễn.

$sudo vim /etc/fstab

     /swapfile       none    swap    sw      0       0 

Nguồn và thông tin thêm có thể được tìm thấy ở đây .


1
Điều đó có khắc phục được cùng một vấn đề hay một số vấn đề khác không?
Dima Tisnek

Điều này đã làm điều đó cho tôi tại CentOS 6.4. Đã gặp lỗi khi cài đặt awstats, cảm ơn.
Ruslan Abuzant

Mặc dù điều này cho phép tôi thực thi Mã, nhưng nó không thực sự giải quyết được vấn đề, có thể nằm trong thư viện tôi sử dụng.
philmaweb,

1
Bạn đã khắc phục sự cố của tôi. Cảm ơn! +1
sscirrus

8

hoán đổi có thể không phải là cá trích đỏ được đề xuất trước đó. Quy trình trăn lớn như thế nào được đề cập ngay trước ENOMEM?

Trong kernel 2.6, /proc/sys/vm/swappinesskiểm soát mức độ mạnh mẽ của kernel sẽ chuyển sang hoán đổi, và overcommit*các tệp tin có thể phân bổ bao nhiêu và chính xác như thế nào trong bộ nhớ bằng nháy mắt và gật đầu. Giống như trạng thái quan hệ trên facebook của bạn, nó phức tạp .

... nhưng hoán đổi thực sự có sẵn theo yêu cầu (theo máy chủ web) ...

nhưng không theo kết quả đầu ra của free(1)lệnh của bạn , lệnh này không hiển thị không gian hoán đổi được phiên bản máy chủ của bạn công nhận. Bây giờ, máy chủ lưu trữ web của bạn chắc chắn có thể biết nhiều hơn tôi về chủ đề này, nhưng hệ thống RHEL / CentOS ảo mà tôi đã sử dụng đã báo cáo hoán đổi có sẵn cho hệ điều hành khách.

Thích ứng với Red Hat KB Điều 15.252 :

Hệ thống Red Hat Enterprise Linux 5 sẽ chạy tốt mà không có không gian hoán đổi miễn là tổng bộ nhớ ẩn danh và bộ nhớ chia sẻ hệ thống V nhỏ hơn khoảng 3/4 dung lượng RAM. .... Hệ thống có 4GB ram trở xuống [được khuyến nghị] có tối thiểu 2GB không gian hoán đổi.

So sánh /proc/sys/vmcài đặt của bạn với cài đặt CentOS 5.3 đơn giản. Thêm tệp hoán đổi. Ratchet xuống swappinessvà xem bạn có còn sống được nữa không.


Cách tốt nhất để kiểm tra kích thước của quá trình python là gì? ps?
davidmytton 03/09/09

một cái gì đó như ps -o user,pid,vsz="Mem(Kb)" -o cmd $PYTHON_PID, hoặc hàng đầu (1), nên làm điều đó.
ăn trộm

7

Để sửa chữa dễ dàng, bạn có thể

echo 1 > /proc/sys/vm/overcommit_memory

nếu bạn chắc chắn rằng hệ thống của bạn có đủ bộ nhớ. Xem Linux over commit heuristic .


1
Cảm ơn bạn rất nhiều! Một giải pháp dễ dàng như vậy, bạn đã cứu được ngày của tôi)
igolkotek 13/02/19

5

Tôi tiếp tục nghi ngờ rằng khách hàng / người dùng của bạn có một số mô-đun hạt nhân hoặc trình điều khiển được tải đang can thiệp vào clone()lệnh gọi hệ thống (có lẽ là một số cải tiến bảo mật không rõ ràng, một cái gì đó như LIDS nhưng khó hiểu hơn?) Hoặc bằng cách nào đó đang lấp đầy một số cấu trúc dữ liệu hạt nhân mà cần thiết cho fork()/ clone()để hoạt động (bảng quy trình, bảng trang, bảng mô tả tệp, v.v.).

Đây là phần có liên quan của fork(2)trang người đàn ông:

LỖI
       EAGAIN fork () không thể phân bổ đủ bộ nhớ để sao chép các bảng trang gốc và phân bổ cấu trúc tác vụ cho
              đứa trẻ.

       EAGAIN Không thể tạo quy trình mới vì đã gặp phải giới hạn tài nguyên RLIMIT_NPROC của người gọi. Đến
              vượt quá giới hạn này, quá trình phải có khả năng CAP_SYS_ADMIN hoặc CAP_SYS_RESOURCE.

       ENOMEM fork () không thể cấp phát các cấu trúc hạt nhân cần thiết vì bộ nhớ quá chật.

Tôi khuyên người dùng nên thử điều này sau khi khởi động vào stock, kernel chung và chỉ tải một tập hợp tối thiểu các mô-đun và trình điều khiển (tối thiểu cần thiết để chạy ứng dụng / tập lệnh của bạn). Từ đó, giả sử nó hoạt động trong cấu hình đó, họ có thể thực hiện tìm kiếm nhị phân giữa cấu hình đó và cấu hình cho thấy sự cố. Đây là cách khắc phục sự cố sysadmin tiêu chuẩn 101.

Dòng có liên quan trong của bạn stracelà:

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

... Tôi biết những người khác đã nói về tính khả dụng của bộ nhớ và trao đổi (và tôi khuyên bạn nên thiết lập ít nhất một phân vùng hoán đổi nhỏ, trớ trêu thay ngay cả khi nó nằm trên đĩa RAM ... các đường dẫn mã qua nhân Linux khi nó có thậm chí một chút hoán đổi có sẵn đã được thực hiện rộng rãi hơn nhiều so với những (đường dẫn xử lý ngoại lệ) mà không có hoán đổi nào khả dụng.

Tuy nhiên tôi nghi ngờ rằng đây vẫn là một con cá trích đỏ.

Thực tế freelà đang báo cáo bộ nhớ 0 (ZERO) được sử dụng bởi bộ nhớ cache và bộ đệm là rất đáng lo ngại. Tôi nghi ngờ rằng kết freequả đầu ra ... và có thể sự cố ứng dụng của bạn ở đây, là do một số mô-đun hạt nhân độc quyền đang can thiệp vào việc cấp phát bộ nhớ theo một cách nào đó.

Theo các trang người đàn ông về lệnh gọi hệ thống fork () / clone () sẽ trả về EAGAIN nếu lệnh gọi của bạn gây ra vi phạm giới hạn tài nguyên (RLIMIT_NPROC) ... tuy nhiên, nó không cho biết liệu EAGAIN có được trả lại hay không bởi các vi phạm RLIMIT * khác. Trong mọi trường hợp nếu mục tiêu / máy chủ của bạn có một số loại Vormetric kỳ lạ hoặc cài đặt bảo mật khác (hoặc ngay cả khi quy trình của bạn đang chạy theo một số chính sách SELinux kỳ lạ) thì nó có thể gây ra lỗi -ENOMEM này.

Nó khá khó có thể là một vấn đề Linux / UNIX chạy bình thường. Bạn có một cái gì đó không chuẩn đang xảy ra ở đó.


1
Máy chủ đang chạy trên nền Media Template (dv) sử dụng Virtuozzo để ảo hóa.
davidmytton

Hãy thử tìm kiếm các bảng tin và hệ thống theo dõi lỗi của Virtuozzo và có lẽ, tìm kiếm các bản nâng cấp cho chính hệ thống con Virtuozzo.
Jim Dennis

2

Bạn đã thử sử dụng:

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

Tôi nghĩ rằng điều này đã khắc phục cùng một vấn đề cho tôi. Nhưng sau đó quá trình của tôi kết thúc bị giết thay vì không thể sinh sản, điều này thậm chí còn tồi tệ hơn ..

Sau một số thử nghiệm, tôi thấy rằng điều này chỉ xảy ra trên các phiên bản cũ hơn của python: nó xảy ra với 2.6.5 nhưng không xảy ra với 2.7.2

Tìm kiếm của tôi đã dẫn tôi đến đây python-close_fds-issue , nhưng việc bỏ đặt closed_fds đã không giải quyết được vấn đề. Nó vẫn rất đáng để đọc.

Tôi phát hiện ra rằng python đang làm rò rỉ bộ mô tả tệp bằng cách chỉ để ý đến nó:

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

Giống như bạn, tôi muốn nắm bắt đầu ra của lệnh và tôi muốn tránh lỗi OOM ... nhưng có vẻ như cách duy nhất là mọi người sử dụng phiên bản Python ít lỗi hơn. Không lý tưởng ...


0

munmap (0xb7d28000, 4096) = 0
write (2, "OSError", 7) = 7

Tôi đã thấy mã cẩu thả trông như thế này:

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

Bạn nên kiểm tra xem đây có phải là những gì đang xảy ra trong mã python hay không. Errno chỉ hợp lệ nếu cuộc gọi hệ thống tiếp tục không thành công.

Đã chỉnh sửa để thêm:

Bạn không nói quá trình này tồn tại bao lâu. Người tiêu dùng có thể có bộ nhớ

  • quá trình phân nhánh
  • cấu trúc dữ liệu không sử dụng
  • thư viện chia sẻ
  • tập tin ánh xạ bộ nhớ

2
Có, nhưng chúng tôi thấy từ sự cố của OP rằng lỗi syscall đầu tiên - từ clone () - là ENOMEM như được báo cáo. Lỗi này được lưu lại cùng với sự cố bộ nhớ thấp của python thông qua xây dựng theo dõi, mặc dù thư viện C errnođược đặt lại nhiều lần trong quá trình này.
ăn cắp vặt vào

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.