Subproses Python. Buka “OSError: [Errno 12] Tidak dapat mengalokasikan memori”

114

Catatan: Pertanyaan ini awalnya ditanyakan di sini tetapi waktu hadiah telah habis meskipun jawaban yang dapat diterima sebenarnya tidak ditemukan. Saya menanyakan kembali pertanyaan ini termasuk semua detail yang diberikan dalam pertanyaan asli.

Skrip python menjalankan serangkaian fungsi kelas setiap 60 detik menggunakan modul sched :

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

Skrip berjalan sebagai proses daemonisasi menggunakan kode di sini .

Sejumlah metode kelas yang disebut sebagai bagian dari doChecks menggunakan modul subprocess untuk memanggil fungsi sistem guna mendapatkan statistik sistem:

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

Ini berjalan dengan baik untuk jangka waktu tertentu sebelum seluruh skrip mengalami crash dengan kesalahan berikut:

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

Output free -m di server setelah skrip rusak adalah:

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

Server menjalankan CentOS 5.3. Saya tidak dapat mereproduksi di kotak CentOS saya sendiri atau dengan pengguna lain yang melaporkan masalah yang sama.

Saya telah mencoba sejumlah hal untuk men-debug ini seperti yang disarankan dalam pertanyaan asli:

  1. Mencatat keluaran free -m sebelum dan sesudah panggilan Popen. Tidak ada perubahan signifikan dalam penggunaan memori yaitu memori tidak digunakan secara bertahap saat skrip dijalankan.

  2. Saya menambahkan close_fds = Sesuai dengan panggilan Popen tetapi ini tidak membuat perbedaan - skrip masih macet dengan kesalahan yang sama. Disarankan di sini dan di sini .

  3. Saya memeriksa batas yang menunjukkan (-1, -1) pada RLIMIT_DATA dan RLIMIT_AS seperti yang disarankan di sini .

  4. Sebuah artikel menyarankan tidak adanya ruang swap mungkin menjadi penyebabnya, tetapi swap sebenarnya tersedia sesuai permintaan (menurut web host) dan ini juga disarankan sebagai penyebab palsu di sini .

  5. Proses ditutup karena itu adalah perilaku menggunakan .communicate () seperti yang dicadangkan oleh kode sumber Python dan komentar di sini .

Seluruh pemeriksaan dapat ditemukan di GitHub di sini dengan fungsi getProcesses yang ditentukan dari baris 442. Ini dipanggil oleh doChecks () mulai dari baris 520.

Skrip dijalankan dengan strace dengan output berikut sebelum crash:

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)                           = ?
davidmytton
sumber
1
runnig dari 'pipe' atau Filescriptors atau kernel-resource yang terkait dengan ini?
Blauohr
Periksa /var/log/messages, atau dmesgperintahkan.
mark4o
Tidak ada di log yang relevan dengan ini.
davidmytton
Apakah Anda pernah mendapatkan solusi untuk ini? Saya memiliki gejala yang sangat mirip. Saya memiliki banyak memori cadangan, tetapi setelah menambahkan swap (seperti yang disarankan beberapa jawaban Anda), masalahnya hilang. Hanya ingin tahu apakah Anda menemukan sesuatu di bulan-bulan antara dulu dan sekarang. - terima kasih!
dpb
Saya mengalami masalah yang sama tetapi tidak ada penyelesaian - ada ide?

Jawaban:

88

Sebagai aturan umum (yaitu di vanili kernel), fork/ clonekegagalan dengan ENOMEM terjadi secara khusus karena baik jujur kepada Allah out-of-memori kondisi ( dup_mm, dup_task_struct, alloc_pid, mpol_dup, mm_initdll parau), atau karena security_vm_enough_memory_mmgagal Anda sementara menegakkan yang kebijakan overcommit .

Mulailah dengan memeriksa vmsize dari proses yang gagal untuk melakukan fork, pada saat percobaan fork, dan kemudian bandingkan dengan jumlah memori bebas (fisik dan swap) yang berkaitan dengan kebijakan overcommit (colokkan angkanya.)

Dalam kasus khusus Anda, perhatikan bahwa Virtuozzo memiliki pemeriksaan tambahan dalam penegakan komitmen berlebihan . Selain itu, saya tidak yakin seberapa besar kendali yang benar-benar Anda miliki, dari dalam penampung Anda, atas konfigurasi swap dan overcommit (untuk memengaruhi hasil penegakan.)

Sekarang, untuk benar-benar bergerak maju, saya akan mengatakan Anda memiliki dua opsi :

  • beralih ke instance yang lebih besar, atau
  • lakukan upaya pengkodean agar lebih efektif mengontrol jejak memori skrip Anda

CATATAN bahwa upaya pengkodean mungkin sia-sia jika ternyata itu bukan Anda, tetapi beberapa orang lain bertumpuk dalam contoh yang berbeda di server yang sama saat Anda menjalankan amock.

Dari segi memori, kita sudah tahu bahwa subprocess.Popenuse fork/ clone under the hood , yang berarti bahwa setiap kali Anda memanggilnya, Anda meminta sekali lagi memori sebanyak Python sudah menghabiskan , yaitu dalam ratusan MB tambahan, semuanya untuk kemudian exec10kB kecil yang dapat dieksekusi seperti freeatau ps. Dalam kasus kebijakan overcommit yang tidak menguntungkan, Anda akan segera melihatnya ENOMEM.

Alternatif untuk forkyang tidak memiliki tabel halaman induk ini dll. Masalah salin adalah vforkdan posix_spawn. Tetapi jika Anda tidak ingin menulis ulang potongan subprocess.Popendalam istilah vfork/ posix_spawn, pertimbangkan untuk menggunakan suprocess.Popenhanya sekali, di awal skrip Anda (ketika jejak memori Python minimal), untuk menelurkan skrip shell yang kemudian menjalankan free/ ps/ sleepdan apa pun di a loop sejajar dengan skrip Anda; polling keluaran skrip atau baca secara sinkron, mungkin dari utas terpisah jika Anda memiliki hal lain yang harus ditangani secara asinkron - lakukan pemrosesan data Anda dengan Python tetapi serahkan percabangan ke proses bawahan.

NAMUN , dalam kasus khusus Anda, Anda dapat melewati permintaan psdan freesama sekali; bahwa informasi sudah tersedia untuk Anda di Python langsung dariprocfs , apakah Anda memilih untuk mengakses sendiri atau melalui perpustakaan dan / atau paket yang ada . Jika psdan freemerupakan satu-satunya utilitas yang Anda jalankan, maka Anda dapat melakukannya subprocess.Popensepenuhnya .

Akhirnya, apa pun yang Anda lakukan sejauh subprocess.Popenyang bersangkutan, jika skrip Anda membocorkan memori, Anda akan tetap terbentur dinding pada akhirnya. Awasi, dan periksa kebocoran memori .

vladr
sumber
7
Saya menemukan bahwa menjalankan gc.collect()sebelum subprocess.Popenmembantu dalam kasus ketika pengumpul sampah tidak berjalan untuk sementara waktu.
letmaik
Saya menulis deamon untuk menangani strategi skrip pembantu: github.com/SeanHayes/errand-boy Saya menggunakannya dalam produksi dengan salah satu klien saya dan masalah "Tidak dapat mengalokasikan memori" hilang.
Seán Hayes
Saya menghargai diagnosis sederhana, misalnya mengikuti /proc/fd/mapsuntuk menentukan apakah memori yang terlalu
terikat
18

Melihat outputnya free -mmenurut saya Anda sebenarnya tidak memiliki memori swap yang tersedia. Saya tidak yakin apakah di Linux swap akan selalu tersedia secara otomatis sesuai permintaan, tetapi saya mengalami masalah yang sama dan tidak ada jawaban di sini yang benar-benar membantu saya. Namun, menambahkan beberapa memori swap, memperbaiki masalah dalam kasus saya jadi karena ini dapat membantu orang lain menghadapi masalah yang sama, saya memposting jawaban saya tentang cara menambahkan swap 1GB (di Ubuntu 12.04 tetapi seharusnya berfungsi sama untuk distribusi lain.)

Anda dapat terlebih dahulu memeriksa apakah ada memori swap yang diaktifkan.

$sudo swapon -s

jika kosong, itu berarti Anda tidak mengaktifkan swap. Untuk menambahkan swap 1GB:

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

Tambahkan baris berikut ke fstabuntuk membuat swap permanen.

$sudo vim /etc/fstab

     /swapfile       none    swap    sw      0       0 

Sumber dan informasi lebih lanjut dapat ditemukan di sini .

Nima
sumber
1
Apakah itu memperbaiki masalah yang sama atau masalah lainnya?
Dima Tisnek
Ini melakukannya untuk saya di CentOS 6.4. Menghadapi kesalahan saat memasang awstats, terima kasih.
Ruslan Abuzant
Meskipun ini memungkinkan saya mengeksekusi Kode, itu tidak benar-benar mengatasi masalah, yang mungkin terletak pada perpustakaan yang saya gunakan.
philmaweb
1
Anda memperbaiki masalah saya. Terima kasih! +1
sscirrus
8

swap mungkin bukan ikan haring merah yang disarankan sebelumnya. Seberapa besar proses python yang dimaksud sebelum ENOMEM?

Di bawah kernel 2.6, /proc/sys/vm/swappinessmengontrol seberapa agresif kernel akan beralih ke swap, dan overcommit*mencatat seberapa banyak dan seberapa tepatnya kernel dapat membagi memori dengan kedipan dan anggukan. Seperti status hubungan facebook Anda, itu rumit .

... tetapi swap sebenarnya tersedia sesuai permintaan (menurut host web) ...

tetapi tidak sesuai dengan output dari free(1)perintah Anda , yang menunjukkan tidak ada ruang swap yang dikenali oleh instance server Anda. Sekarang, host web Anda mungkin tahu lebih banyak daripada saya tentang topik ini, tetapi sistem RHEL / CentOS virtual yang saya gunakan telah melaporkan swap tersedia untuk OS tamu.

Mengadaptasi Red Hat KB Article 15252 :

Sistem Red Hat Enterprise Linux 5 akan berjalan dengan baik tanpa ruang swap sama sekali selama jumlah memori anonim dan memori bersama sistem V kurang dari sekitar 3/4 jumlah RAM. .... Sistem dengan RAM 4GB atau kurang [disarankan untuk memiliki] ruang swap minimal 2GB.

Bandingkan /proc/sys/vmpengaturan Anda dengan instalasi CentOS 5.3 biasa. Tambahkan file swap. Ratchet turun swappinessdan lihat apakah Anda hidup lebih lama.

pilcrow
sumber
Bagaimana cara terbaik untuk memeriksa ukuran proses python? ps?
davidmytton
sesuatu seperti ps -o user,pid,vsz="Mem(Kb)" -o cmd $PYTHON_PID, atau top (1), harus melakukannya.
pilcrow
7

Untuk perbaikan yang mudah, Anda bisa

echo 1 > /proc/sys/vm/overcommit_memory

jika Anda yakin bahwa sistem Anda memiliki cukup memori. Lihat Linux over commit heuristic .

serv-inc
sumber
1
Terima kasih banyak! Solusi yang begitu mudah, Anda menyelamatkan hari saya)
igolkotek
5

Saya terus mencurigai bahwa pelanggan / pengguna Anda memiliki beberapa modul kernel atau driver yang dimuat yang mengganggu clone()panggilan sistem (mungkin beberapa peningkatan keamanan yang tidak jelas, sesuatu seperti LIDS tetapi lebih tidak jelas?) Atau entah bagaimana mengisi beberapa struktur data kernel yang diperlukan untuk fork()/ clone()untuk mengoperasikan (tabel proses, tabel halaman, tabel deskriptor file, dll).

Inilah bagian yang relevan dari fork(2)halaman manual:

ERRORS
       EAGAIN fork () tidak dapat mengalokasikan memori yang cukup untuk menyalin tabel halaman induk dan mengalokasikan struktur tugas untuk
              anak.

       EAGAIN Tidak mungkin membuat proses baru karena batas sumber daya RLIMIT_NPROC pemanggil telah ditemukan. Untuk
              melebihi batas ini, proses harus memiliki kemampuan CAP_SYS_ADMIN atau CAP_SYS_RESOURCE.

       ENOMEM fork () gagal mengalokasikan struktur kernel yang diperlukan karena memorinya terbatas.

Saya sarankan agar pengguna mencoba ini setelah boot ke dalam sebuah stok, kernel generik dan hanya dengan set minimal modul dan driver yang dimuat (minimal diperlukan untuk menjalankan aplikasi / skrip Anda). Dari sana, dengan asumsi itu berfungsi dalam konfigurasi itu, mereka dapat melakukan pencarian biner antara itu dan konfigurasi yang menunjukkan masalah tersebut. Ini adalah pemecahan masalah sysadmin standar 101.

Baris yang relevan di Anda straceadalah:

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

... Saya tahu orang lain telah membicarakan tentang swap dan ketersediaan memori (dan saya akan merekomendasikan agar Anda mengatur setidaknya partisi swap kecil, ironisnya bahkan jika itu ada di disk RAM ... jalur kode melalui kernel Linux ketika ada bahkan sedikit swap yang tersedia telah dilakukan jauh lebih luas daripada yang (jalur penanganan pengecualian) di mana tidak ada swap yang tersedia.

Namun saya curiga ini masih ikan haring.

Fakta bahwa freemelaporkan 0 (ZERO) memory yang digunakan oleh cache dan buffer sangat mengganggu. Saya menduga bahwa freeoutput ... dan mungkin masalah aplikasi Anda di sini, disebabkan oleh beberapa modul kernel berpemilik yang mengganggu alokasi memori dalam beberapa cara.

Menurut halaman manual untuk fork () / clone () panggilan sistem fork () harus mengembalikan EAGAIN jika panggilan Anda menyebabkan pelanggaran batas sumber daya (RLIMIT_NPROC) ... namun, tidak disebutkan apakah EAGAIN akan dikembalikan oleh pelanggaran RLIMIT * lainnya. Bagaimanapun jika target / host Anda memiliki semacam Vormetric aneh atau pengaturan keamanan lainnya (atau bahkan jika proses Anda berjalan di bawah beberapa kebijakan SELinux yang aneh) maka itu mungkin menyebabkan kegagalan -ENOMEM ini.

Ini sangat tidak mungkin menjadi masalah Linux / UNIX run-of-the-mill normal. Ada sesuatu yang tidak standar di sana.

Jim Dennis
sumber
1
Server berjalan pada basis Media Template (dv) yang menggunakan Virtuozzo untuk virtualisasi.
davidmytton
Coba cari papan pesan Virtuozzo dan sistem pelacakan bug dan, mungkin, cari peningkatan ke subsistem Virtuozzo itu sendiri.
Jim Dennis
2

Sudahkah Anda mencoba menggunakan:

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

Saya pikir ini telah memperbaiki masalah yang sama persis untuk saya. Tapi kemudian proses saya berakhir terbunuh bukannya gagal bertelur, yang bahkan lebih buruk ..

Setelah beberapa pengujian saya menemukan bahwa ini hanya terjadi pada versi python yang lebih lama: itu terjadi dengan 2.6.5 tetapi tidak dengan 2.7.2

Pencarian saya telah membawa saya ke sini python-close_fds-issue , tetapi membatalkan pengaturan closed_fds tidak menyelesaikan masalah. Ini masih layak dibaca.

Saya menemukan bahwa python membocorkan deskriptor file hanya dengan mengawasinya:

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

Seperti Anda, saya ingin menangkap keluaran perintah, dan saya ingin menghindari kesalahan OOM ... tetapi sepertinya satu-satunya cara bagi orang-orang untuk menggunakan versi Python yang tidak terlalu bermasalah. Tidak ideal ...

totaam
sumber
0

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

Saya telah melihat kode ceroboh yang terlihat seperti ini:

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

Anda harus memeriksa untuk melihat apakah ini yang terjadi pada kode python. Errno hanya valid jika panggilan sistem yang dilanjutkan gagal.

Diedit untuk menambahkan:

Anda tidak mengatakan berapa lama proses ini berlangsung. Kemungkinan konsumen memori

  • proses bercabang
  • struktur data yang tidak digunakan
  • perpustakaan bersama
  • file yang dipetakan memori
codeDr
sumber
2
Ya, tapi kami melihat dari lapisan OP bahwa kegagalan syscall pertama - dari clone () - adalah ENOMEM seperti yang dilaporkan. Kesalahan ini dipertahankan selama python memiliki memori rendah yang tersandung melalui konstruksi pelacakan, meskipun perpustakaan-C errnodisetel ulang berkali-kali di sepanjang jalan.
pilcrow