Kesalahan Fatal: Diizinkan Ukuran Memori 134217728 Bytes Lelah (CodeIgniter + XML-RPC)


618

Saya memiliki banyak sistem klien titik penjualan (POS) yang secara berkala mengirim data penjualan baru ke satu database terpusat, yang menyimpan data ke dalam satu database besar untuk pembuatan laporan.

POS klien didasarkan pada PHPPOS, dan saya telah mengimplementasikan modul yang menggunakan pustaka XML-RPC standar untuk mengirim data penjualan ke layanan. Sistem server dibangun di atas CodeIgniter, dan menggunakan pustaka XML-RPC dan XML-RPCS untuk komponen layanan web. Setiap kali saya mengirim banyak data penjualan (sedikitnya 50 baris dari tabel penjualan, dan baris individual dari sales_item yang berkaitan dengan setiap item dalam penjualan) saya mendapatkan kesalahan berikut:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 54 bytes)

128M adalah nilai default php.ini, tapi saya berasumsi itu adalah angka yang sangat besar untuk dipecahkan. Bahkan, saya bahkan telah mencoba mengatur nilai ini ke 1024M, dan yang diperlukan hanyalah waktu lebih lama untuk melakukan kesalahan.

Adapun langkah-langkah yang telah saya ambil, saya sudah mencoba menonaktifkan semua pemrosesan di sisi server, dan telah memasang itu untuk mengembalikan respons kalengan terlepas dari input. Namun, saya percaya masalahnya terletak pada pengiriman data yang sebenarnya. Saya bahkan sudah mencoba menonaktifkan waktu eksekusi skrip maksimum untuk PHP, dan itu masih error.


5
Saya agak bingung ... di mana kesalahan terjadi - di klien atau server? Dan pada tahap mana ... pengiriman klien, penerimaan server, pemrosesan server, pengiriman server, penerimaan klien atau pemrosesan klien?
Greg

2
Kesalahan tampaknya terjadi baik selama pengiriman klien, atau penerimaan server. Saya sudah mencoba menonaktifkan semua pemrosesan di sisi server, dan mencuranginya untuk mengirim respons kalengan terlepas dari data yang dikirim. Kesalahan terjadi jika saya mengirim sejumlah data tertentu. Saya mengubah pengaturan PHP.ini.
ArcticZero

42
batas memori adalah 128MB, ini_set('memory_limit', '256M');

9
Ringkasan menurunkan semua jawaban "abaikan saja kebocoran", orang-orang yang mengacaukan CodeIgniter dengan Drupal dan orang-orang yang hanya menyalin dan menempelkan jawaban orang lain untuk mendapatkan poin. Kualitas jawaban yang satu ini sangat buruk.
Matti Virkkunen

Jawaban:


697

Mengubah memory_limitoleh ini_set('memory_limit', '-1');adalah tidak solusi yang tepat. Tolong jangan lakukan itu.

Kode PHP Anda mungkin mengalami kebocoran memori di suatu tempat dan Anda memberi tahu server untuk hanya menggunakan semua memori yang diinginkan. Anda tidak akan memperbaiki masalah sama sekali. Jika Anda memantau server Anda, Anda akan melihat bahwa sekarang mungkin menggunakan sebagian besar RAM dan bahkan menukar ke disk.

Anda mungkin harus mencoba melacak kode yang menyinggung dalam kode Anda dan memperbaikinya.


174
@ Jeff Anda mungkin benar 95% dari waktu. Namun, ada kalanya Anda benar-benar membutuhkan lebih banyak memori. Misalnya, katakanlah aplikasi Anda memuat sejumlah besar data ke dalam memori untuk diproses (misalnya, Bill of Material dengan komponen 15k). Ini tidak selalu terjadi bahwa kode ini bermasalah, kadang-kadang Anda hanya perlu sedikit lebih banyak memori (misalnya 256M, bukan 128M). Namun saya setuju bahwa pengaturan ke -1 sangat buruk. Tetapi menyesuaikan batas memori untuk situasi yang masuk akal saat run-time bisa diterima.
Pyrite

24
@pyrite ya Anda benar bahwa kadang-kadang suatu proses membutuhkan lebih banyak memori tetapi Anda harus meningkatkan batas memori ke sejumlah logis seperti 256MB seperti yang Anda katakan atau 512MB mengapa tidak TAPI bukan -1;)
Lukas Lukac

9
@ jeff Saya setuju sepenuhnya, nilai -1bisa berguna hanya di lingkungan dev untuk tujuan pengujian.
Esolitos

4
@ Menulis dalam kasus yang Anda beri nama untuk 5% sisanya, baca data dalam potongan dan gunakan pekerja untuk memprosesnya alih-alih menggunakan lebih banyak memori. Solusi ini akan menskala juga sementara saran Anda tidak akan berfungsi kecuali Anda terus memasukkan lebih banyak memori ke server Anda seiring waktu jika data bertambah.
burzum

2
Dalam cara yang paling umum masalah ini dalam ORM ketika Anda mencoba untuk mengambil semua data yang lebih banyak batas memori php. Misalnya ketika Anda mencoba menghasilkan laporan bulanan.
Stepchik

213

ini_set('memory_limit', '-1');mengabaikan batas memori PHP default .


16
@williamcarswell; -1adalah nilai yang dipahami oleh PHP sebagai tidak terbatas dalam konteks ini.
Alix Axel

7
@ ArseniuszŁozicki - ini juga akan menghabiskan sumber daya yang tidak dapat disimpan oleh server .
Ken Williams

124
Malu ini mendapat banyak upvotes. Menyetelnya ke nilai yang akurat, dengan editan php.ini atau ini_set, adalah solusi yang benar-benar valid ketika orang membutuhkan lebih banyak memori. Menetapkannya menjadi tidak terbatas adalah peretasan berbahaya :(
Jeff Davis

24
@ user1767586 lalu setel ke nilai yang waras. Anda bisa mencegah skrip dari melemparkan kesalahan dengan mengaturnya ke 1024M. Jika jawaban ini mengatakan ini_set ('memory_limit', '1024M'); Anda dapat menyalin dan menempelkannya dan menjadi ok. Dengan mengaturnya ke -1 Anda mengatur diri Anda untuk memiliki skrip yang menghabiskan semua memori. Apalagi jika Anda melakukan ini secara rutin. Menempatkan "berbahaya" dalam tanda kutip tidak membuatnya menjadi kurang berbahaya. Anda benar-benar dapat menyemprot server host Anda. Mungkin mulai menghancurkan data. Saya tidak tahu, mungkin kehilangan pekerjaan Anda? Kedengarannya sangat berbahaya bagiku. : |
Jeff Davis

3
Sedih melihat bahwa jawaban untuk +161 suara dan -3 suara adalah sama :(
akarthik10

130

Cara yang benar adalah mengedit php.inifile Anda . Edit memory_limitnilai keinginan Anda.

Seperti dari pertanyaan Anda, 128M(yang merupakan batas default) telah terlampaui, jadi ada sesuatu yang salah dengan kode Anda karena tidak boleh terlalu banyak.

Jika Anda tahu mengapa dibutuhkan sebanyak itu dan Anda ingin mengizinkannya ditetapkan memory_limit = 512Matau lebih tinggi dan Anda harus baik.


7
Jujur, jika Anda melakukan caching sejumlah data serius, ini adalah jawaban yang benar. 128M tidak cukup untuk skrip tertentu. 512M atau 1024M sering kali sudah cukup, tetapi Anda harus memutuskan kasus per kasus.
Jeff Davis

2
Yeha, namun cobalah untuk menghindari penggunaan memori yang besar, jika jumlah pengguna akan lebih banyak
Basav

2
memory_limit = -1; atur di php.ini

2
@YumYumYum Yang menghapus memory_limit, yang hanya Anda inginkan jika Anda memantau penggunaan memori dengan cara lain. OS akan mematikan proses jika mengambil sejumlah besar memori di beberapa titik dengan cara apa pun.
Flimm

Jadi jika Anda menjalankan skrip yang menggunakan banyak memori, tetapi Anda hanya perlu menjalankannya sekali saja, dapatkah Anda hanya menambah batas memori untuk proses pada saat eksekusi, kemudian turunkan batas memori Anda lagi setelah satu kali Anda skrip berjalan?
chromechris

95

Alokasi memori untuk PHP dapat disesuaikan secara permanen, atau sementara.

Secara permanen

Anda dapat mengubah secara permanen alokasi memori PHP dengan dua cara.

Jika Anda memiliki akses ke php.inifile Anda, Anda dapat mengedit nilai untuk memory_limitnilai keinginan Anda.

Jika Anda tidak memiliki akses ke php.inifile Anda (dan webhost Anda mengizinkannya), Anda dapat mengganti alokasi memori melalui .htaccessfile Anda . Tambahkan php_value memory_limit 128M(atau apa pun alokasi yang Anda inginkan).

Sementara

Anda dapat menyesuaikan alokasi memori dengan cepat dari dalam file PHP. Anda cukup memiliki kode ini_set('memory_limit', '128M');(atau apa pun alokasi yang Anda inginkan). Anda dapat menghapus batas memori (meskipun mesin atau batas instance mungkin masih berlaku) dengan mengatur nilai ke "-1".


2
Terima kasih saya tidak berpikir untuk memeriksa apakah seseorang telah menetapkan nilai di .htaccess yang menimpa php.ini dan saya tidak tahu mengapa 1
HostMyBus

61

Sangat mudah untuk mendapatkan kebocoran memori dalam skrip PHP - terutama jika Anda menggunakan abstraksi, seperti ORM. Coba gunakan Xdebug untuk profil skrip Anda dan cari tahu di mana semua memori itu pergi.


1
Saya akan mencoba Xdebug. Saya belum pernah menggunakannya sebelumnya, jadi saya harus membacanya. Terima kasih untuk balasannya! Semoga saya menemukan jawaban untuk ini segera ...
ArcticZero

34
Ingat bahwa PHP menggunakan penghitungan referensi untuk mengelola memori. Jadi jika Anda memiliki referensi melingkar, atau variabel global, objek-objek itu tidak akan didaur ulang. Itu biasanya akar kebocoran memori di PHP.
troelskn

Xdebug menunjukkan bahwa pustaka Xmlrpc.php CI bertanggung jawab atas kebocoran memori saya. Kebetulan, apakah akan ada masalah dengan perpustakaan XML-RPC CodeIgniter yang harus saya ketahui? Saya telah mencoba menonaktifkan semua pemrosesan di sisi server, dan masih kehabisan memori jika saya memberinya cukup data.
ArcticZero

1
Saya tidak tahu / menggunakan CI, jadi saya tidak tahu. Tetapi Anda mungkin harus mencoba untuk menemukan objek yang tidak dibebaskan setelah digunakan - kemungkinan besar karena referensi siklik. Ini pekerjaan detektif.
troelskn

1
Ini adalah satu-satunya jawaban di sini yang menyarankan sebenarnya mengatasi masalah. Jawaban lain menghidupkan memori untuk membalut suatu gejala dan mengabaikan penyakit .
Chris Baker

56

Ketika menambahkan 22,5 juta catatan ke dalam array dengan array_push saya terus mendapatkan "kehabisan memori" kesalahan fatal di sekitar 20 juta catatan menggunakan 4Gsebagai batas memori dalam file php.ini. Untuk memperbaikinya, saya menambahkan pernyataan

$old = ini_set('memory_limit', '8192M');

di bagian atas file. Sekarang semuanya bekerja dengan baik. Saya tidak tahu apakah PHP memiliki kebocoran memori. Itu bukan pekerjaan saya, saya juga tidak peduli. Saya hanya harus menyelesaikan pekerjaan saya, dan ini berhasil.

Program ini sangat sederhana:

$fh = fopen($myfile);
while (!feof($fh)) {
    array_push($file, stripslashes(fgets($fh)));
}
fclose($fh);

Kesalahan fatal menunjuk ke baris 3 sampai saya meningkatkan batas memori, yang menghilangkan kesalahan.


10
Anda maksud ini_set('memory_limit', '8192M');?
Gogol

2
Betapa mewahnya memiliki waktu untuk pergi dan mengoptimalkan skrip untuk sesuatu seperti itu. Atau teliti dan bandingkan serta pelajari alat ETL atau semacamnya. Di dunia nyata, kita mendongkrak cadangan memori naik, melakukan hal itu, dan melanjutkan.
Matthew Poer

45

Saya terus mendapatkan kesalahan ini, bahkan dengan memory_limitset in php.ini, dan nilai pembacaan dengan benar phpinfo().

Dengan mengubahnya dari ini:

memory_limit=4G

Untuk ini:

memory_limit=4096M

Ini memperbaiki masalah di PHP 7.


23

Ketika Anda melihat kesalahan di atas - terutama jika (tried to allocate __ bytes)nilainya rendah, itu bisa menjadi indikator loop tak terbatas, seperti fungsi yang menyebut dirinya sendiri tanpa jalan keluar:

function exhaustYourBytes()
{
    return exhaustYourBytes();
}

19

Setelah mengaktifkan dua baris ini, mulai bekerja:

; Determines the size of the realpath cache to be used by PHP. This value should
; be increased on systems where PHP opens many files to reflect the quantity of
; the file operations performed.
; http://php.net/realpath-cache-size
realpath_cache_size = 16k

; Duration of time, in seconds for which to cache realpath information for a given
; file or directory. For systems with rarely changing files, consider increasing this
; value.
; http://php.net/realpath-cache-ttl
realpath_cache_ttl = 120


19

Anda dapat memperbaiki ini dengan benar dengan mengubah memory_limitfastcgi / fpm:

$vim /etc/php5/fpm/php.ini

Ubah memori, seperti dari 128 menjadi 512, lihat di bawah

; Maximum amount of memory a script may consume (128 MB)
; http://php.net/memory-limit
memory_limit = 128M

untuk

; Maximum amount of memory a script may consume (128 MB)
; http://php.net/memory-limit
memory_limit = 512M

18

Direktori root situs Anda:

ini_set('memory_limit', '1024M');

1
ini bekerja untuk saya. suka satu solusi garis. +1 untuk kesederhanaan
Steve C

14

Ubah batas memori dalam file php.ini dan restart Apache. Setelah restart, jalankan phpinfo (); berfungsi dari file PHP apa pun untuk memory_limitkonfirmasi perubahan.

memory_limit = -1

Batas memori -1 berarti tidak ada batas memori yang ditetapkan. Sekarang sudah maksimal.


13

Untuk pengguna Drupal, ini jawaban Chris Lane dari:

ini_set('memory_limit', '-1');

bekerja tetapi kita harus meletakkannya tepat setelah pembukaan

<?php

beri tag pada file index.php di direktori root situs Anda.


13

Di Drupal 7, Anda dapat mengubah batas memori dalam file settings.php yang terletak di situs / folder default Anda. Sekitar baris 260, Anda akan melihat ini:

ini_set('memory_limit', '128M');

Bahkan jika pengaturan php.ini Anda cukup tinggi, Anda tidak akan dapat mengkonsumsi lebih dari 128 MB jika ini tidak diatur dalam file Drupal settings.php Anda.


1
Tidak di Drupal7 tidak ada string kode seperti itu di settings.php
FLY

Tidak ada string dalam pengaturan.php untuk drupal 6
AllisonC

12

Daripada mengubah memory_limitnilai dalam php.inifile Anda , jika ada bagian dari kode Anda yang dapat menggunakan banyak memori, Anda bisa menghapus memory_limitsebelum bagian itu berjalan, dan kemudian menggantinya setelah itu.

$limit = ini_get('memory_limit');
ini_set('memory_limit', -1);
// ... do heavy stuff
ini_set('memory_limit', $limit);

7

PHP 5.3+ memungkinkan Anda untuk mengubah batas memori dengan menempatkan .user.inifile di public_htmlfolder. Cukup buat file di atas dan ketik baris berikut di dalamnya:

memory_limit = 64M

Beberapa host cPanel hanya menerima metode ini.


7

Halaman rusak?

Masukkan deskripsi gambar di sini

(Ini terjadi ketika MySQL harus query baris besar. Secara default, memory_limitdiatur ke kecil, yang lebih aman untuk perangkat keras.)

Anda dapat memeriksa status memori yang ada sistem Anda, sebelum menambah php.ini:

# free -m
             total       used       free     shared    buffers     cached
Mem:         64457      63791        666          0       1118      18273
-/+ buffers/cache:      44398      20058
Swap:         1021          0       1021

Di sini saya telah meningkatkannya sebagai berikut dan kemudian lakukan service httpd restartuntuk memperbaiki masalah halaman macet.

# grep memory_limit /etc/php.ini
memory_limit = 512M

Nomor (baris dan kolom?) Mana yang harus dilihat setelah menjalankan free -mperintah untuk memutuskan memory_limit baru?
Kiradotee

7

Cukup tambahkan ini_set('memory_limit', '-1');baris di bagian atas halaman web Anda.

Dan Anda dapat mengatur memori Anda sesuai kebutuhan Anda di tempat -1, ke 16M, dll.


6
Tampaknya ini mengatakan hal yang sama dengan banyak jawaban yang ada. Yang terbaik hanya menambahkan jawaban untuk pertanyaan populer hanya jika materi baru menawarkan sesuatu yang baru.
halfer

6

Bagi mereka yang menggaruk-garuk kepala untuk mencari tahu mengapa di bumi fungsi kecil ini harus menyebabkan kebocoran memori, kadang-kadang karena kesalahan kecil, fungsi mulai memanggil dirinya sendiri secara rekursif selamanya.

Misalnya, kelas proksi yang memiliki nama yang sama untuk fungsi objek yang akan mem-proksi itu.

class Proxy {

    private $actualObject;

    public function doSomething() {

        return $this->actualObjec->doSomething();
    }
}

Kadang-kadang Anda mungkin lupa untuk membawa anggota actualObjec yang kecil itu dan karena proxy sebenarnya memiliki doSomethingmetode itu, PHP tidak akan memberi Anda kesalahan dan untuk kelas besar, itu bisa disembunyikan dari mata selama beberapa menit untuk mencari tahu mengapa bocor memori.


Dan tip lain: Anda dapat memasukkan die('here')kode Anda dan memindahkan pernyataan itu untuk melihat di mana rekursi dimulai.
toddmo

6

Saya memiliki kesalahan di bawah ini saat menjalankan dataset yang lebih kecil dari yang pernah bekerja sebelumnya.

Kesalahan fatal: Ukuran memori yang diijinkan 134217728 byte habis (mencoba mengalokasikan 4096 byte) dalam C: \ workspace \ image_management.php on line 173

Ketika pencarian kesalahan membawa saya ke sini, saya pikir saya akan menyebutkan bahwa itu tidak selalu merupakan solusi teknis dalam jawaban sebelumnya, tetapi sesuatu yang lebih sederhana. Dalam kasus saya itu adalah Firefox. Sebelum saya menjalankan program itu sudah menggunakan 1.157 MB.

Ternyata saya telah menonton video 50 menit sedikit demi sedikit selama beberapa hari dan itu mengacaukan segalanya. Ini semacam perbaikan yang diperbaiki oleh para ahli bahkan tanpa dipikirkan, tetapi bagi orang-orang seperti saya, ada baiknya diingat.


Saya memiliki kejadian serupa di Google Chrome hari ini. Saya sangat skeptis terhadap jawaban ini ... namun, ia mengungkapkan bahwa kelelahan byte saya hilang setelah saya membuka jendela penyamaran dan menembakkan skrip yang sama lagi! Penelitian terus berlanjut.
mickmackusa

2

Menjalankan skrip seperti ini (cron case misalnya): php5 /pathToScript/info.phpmenghasilkan kesalahan yang sama.

Cara yang benar: php5 -cli /pathToScript/info.php


2

Jika Anda menjalankan VPS bertenaga WHM (virtual private server) Anda mungkin menemukan bahwa Anda tidak memiliki izin untuk mengedit PHP.INI secara langsung; sistem harus melakukannya. Di panel kontrol host WHM, buka Konfigurasi LayananEditor Konfigurasi PHP dan ubah memory_limit:

Memperbarui memory_limit pada WHM 11.48.4


2

Saya merasa berguna saat memasukkan atau membutuhkan _dbconnection.php_dan _functions.phpdalam file yang benar-benar diproses, daripada termasuk dalam header. Yang termasuk dalam dirinya sendiri.

Jadi, jika header dan footer Anda disertakan, cukup sertakan semua file fungsional Anda sebelum header dimasukkan.


2

Menggunakan yieldmungkin menjadi solusi juga. Lihat Sintaks generator .

Alih-alih mengubah PHP.inifile untuk penyimpanan memori yang lebih besar, kadang-kadang menerapkan yieldloop di dalam mungkin memperbaiki masalah. Apa yang dilakukan adalah alih-alih membuang semua data sekaligus, ia membacanya satu per satu, menghemat banyak penggunaan memori.


2
PHP.ini? Bukan php.ini?
Peter Mortensen

1

Kesalahan ini kadang-kadang disebabkan oleh bug dalam kode PHP yang menyebabkan rekursi yang melibatkan penanganan pengecualian dan kemungkinan operasi lainnya. Sayangnya, saya belum bisa membuat contoh kecil.

Dalam kasus ini, yang telah terjadi pada saya beberapa kali, set_time_limit gagal, dan browser terus berusaha memuat output PHP, baik dengan infinite loop atau dengan pesan kesalahan fatal yang menjadi topik pertanyaan ini.

Dengan mengurangi ukuran alokasi yang diizinkan dengan menambahkan

ini_set('memory_limit','1M');

mendekati awal kode Anda, Anda harus dapat mencegah kesalahan fatal.

Maka Anda mungkin dibiarkan dengan program yang berakhir, tetapi masih sulit untuk debug.

Pada titik ini masukkan BreakLoop()panggilan di dalam program Anda untuk mendapatkan kontrol dan mencari tahu apa loop atau rekursi dalam program Anda yang menyebabkan masalah.

Definisi BreakLoop adalah sebagai berikut:

function BreakLoop($MaxRepetitions=500,$LoopSite="unspecified")
    {
    static $Sites=[];
    if (!@$Sites[$LoopSite] || !$MaxRepetitions)
        $Sites[$LoopSite]=['n'=>0, 'if'=>0];
    if (!$MaxRepetitions)
        return;
    if (++$Sites[$LoopSite]['n'] >= $MaxRepetitions)
        {
        $S=debug_backtrace(); // array_reverse
        $info=$S[0];
        $File=$info['file'];
        $Line=$info['line'];
        exit("*** Loop for site $LoopSite was interrupted after $MaxRepetitions repetitions. In file $File at line $Line.");
        }
    } // BreakLoop

Argumen $ LoopSite dapat menjadi nama fungsi dalam kode Anda. Ini tidak benar-benar diperlukan, karena pesan kesalahan yang Anda dapatkan akan mengarahkan Anda ke baris yang berisi panggilan BreakLoop ().


-1

Dalam kasus saya itu adalah masalah singkat dengan cara fungsi ditulis. Kebocoran memori dapat disebabkan oleh menetapkan nilai baru ke variabel input fungsi, misalnya:

/**
* Memory leak function that illustrates unintentional bad code
* @param $variable - input function that will be assigned a new value
* @return null
**/
function doSomehting($variable){
    $variable = 'set value';
    // Or
    $variable .= 'set value';
}

-6

Ketika saya menghapus baris berikut dari kode saya, semua berfungsi dengan baik!

set_include_path(get_include_path() . get_include_path() . '/phpseclib');
include_once('Net/SSH2.php');
include_once('Net/SFTP.php');

Baris-baris ini termasuk dalam setiap file yang saya jalankan. Saat menjalankan file satu per satu, semuanya bekerja dengan baik, tetapi ketika menjalankan semua file bersama-sama saya mendapatkan masalah kebocoran memori. Entah bagaimana "include_once" tidak termasuk hal sekali, atau saya melakukan sesuatu yang salah ...


set_include_path(get_include_path() . get_include_path().'/phpseclib'); Ini akan menambahkan path '/ phpseclib' satu kali untuk setiap file yang memiliki baris ... sehingga ia dapat menambahkannya berkali-kali! Saya sarankan meletakkannya di file pengaturan dan include_oncefile pengaturan.
Farfromunique
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.