Önemli Hata: İzin Verilen Bellek Boyutu 134217728 Bayt Bitti (CodeIgniter + XML-RPC)


618

Rapor oluşturma için verileri büyük bir veritabanında depolayan tek bir merkezi veritabanına periyodik olarak yeni satış verileri gönderen bir dizi müşteri satış noktası (POS) sistemim var.

İstemci POS PHPPOS dayanmaktadır ve hizmet satış verileri göndermek için standart XML-RPC kitaplığını kullanan bir modül uyguladık. Sunucu sistemi CodeIgniter üzerine kuruludur ve webservice bileşeni için XML-RPC ve XML-RPCS kitaplıklarını kullanır. Çok fazla satış verisi gönderdiğimde (satış tablosundan en az 50 satır ve satış içindeki her bir öğeyle ilgili satış_birimlerinden ayrı satırlar) aşağıdaki hatayı alıyorum:

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

128M varsayılan değerdir php.ini, ancak bunun çok büyük bir sayı olduğunu varsayıyorum. Aslında, bu değeri 1024M'ye ayarlamayı bile denedim ve tüm yaptığı hata yapmak için daha uzun zaman alıyor.

Attığım adımlara gelince, sunucu tarafındaki tüm işlemleri devre dışı bırakmayı denedim ve girişe bakılmaksızın hazır bir yanıt döndürmek için ayarladım. Ancak, sorunun verilerin gerçek gönderilmesinden kaynaklandığına inanıyorum. Hatta PHP için maksimum komut dosyası yürütme süresini devre dışı bırakmayı denedim ve hala hata veriyor.


5
Biraz kafam karıştı ... hata nerede oluşuyor - istemci veya sunucuda? Ve hangi aşamada ... istemci gönderme, sunucu alma, sunucu işleme, sunucu gönderme, istemci alma veya istemci işleme?
Greg

2
Hata, istemci gönderme sırasında veya sunucu alma sırasında ortaya çıkıyor gibi görünüyor. Tüm sunucu tarafı işlemeyi devre dışı bırakmayı ve gönderilen veriye bakılmaksızın hazır bir yanıt göndermeyi denedim. Hata belirli bir miktarda veri gönderirse oluşur. PHP.ini ayarını değiştiriyorum.
ArcticZero

42
bellek limiti 128MB, ini_set('memory_limit', '256M');

9
Özet, tüm "sızıntıyı görmezden gel" cevaplarını, CodeIgniter'ı Drupal ile karıştırmış olanları ve puan almak için diğer insanların cevaplarını kopyalayıp yapıştırmış olanları reddetti. Bu sorudaki cevapların kalitesi uçsuz bucaksızdır.
Matti Virkkunen

Yanıtlar:


697

memory_limitBy ini_set('memory_limit', '-1');değerini değiştirmek uygun bir çözüm değildir . Lütfen bunu yapma.

PHP kodunuzda bir yerde bellek sızıntısı olabilir ve sunucuya sadece istediği tüm belleği kullanmasını söylersiniz. Sorunu hiç çözemezdiniz. Sunucunuzu izlerseniz, şimdi muhtemelen RAM'in çoğunu kullandığını ve hatta diske değiştiğini göreceksiniz.

Muhtemelen kodunuzdaki rahatsız edici kodu bulmaya ve düzeltmeye çalışmalısınız.


173
@Jeff muhtemelen% 95 haklısın. Ancak, aslında daha fazla belleğe ihtiyaç duyduğunuz zamanlar vardır. Örneğin, uygulamanızın işlenmek üzere belleğe büyük miktarda veri yüklediğini varsayalım (15k bileşenli bir Malzeme Listesi). Kod her zaman böyle değildir, bazen biraz daha fazla belleğe ihtiyacınız vardır (örneğin 128M yerine 256M). Ancak -1 olarak ayarlamanın korkunç derecede kötü olduğunu kabul ediyorum. Ancak, bellek sınırını çalışma zamanında makul durumlar için ayarlamak imho'dur.
Pirit

24
@pyrite evet haklısın, bazen bir işlem daha fazla bellek gerektiriyor, ancak bellek sınırını dediğin gibi 256MB veya mantıksal bir miktar kadar artırmalısın ya da 512MB neden -1 olmasın?)
Lukas Lukac

9
@jeff Tamamen katılıyorum, bir değeri yalnızca geliştirme ortamlarında test amacıyla -1yararlı olabilir .
Esolitos

4
@ Kalan% 5 için adlandırdığınız durumlarda pirit, verileri parçalar halinde okur ve daha fazla bellek kullanmak yerine bir işçi kullanır. Veriler büyüdükçe zamanla sunucunuza daha fazla bellek doldurmaya devam etmeniz dışında önerileriniz çalışmazken bu çözüm de ölçeklenir.
burzum

2
En yaygın şekilde bu sorun ORM çok daha fazla php bellek sınırı getirmeye çalıştığınızda tüm sorunları. Örneğin, aylık rapor oluşturmaya çalıştığınızda.
Stepchik

213

ini_set('memory_limit', '-1');varsayılan PHP bellek sınırını geçersiz kılar .


16
@williamcarswell; -1PHP'nin bu bağlamda sınırsız olarak anladığı bir değerdir .
Alix Axel

7
ArseniuszŁozicki @ - o da sunucu kaynaklarını tüketir olamaz yedek.
Ken Williams

124
Utanç verici bu kadar çok oy alır. Php.ini düzenlemeleri veya ini_set ile doğru bir değere ayarlamak, insanlar daha fazla belleğe ihtiyaç duyduklarında geçerli bir çözümdür. Sınırsız olarak ayarlamak tehlikeli bir saldırıdır :(
Jeff Davis

24
@ user1767586 daha sonra bunu aklı başında bir değere ayarlayın. Betiğin 1024M olarak ayarlayarak hatayı atmasını önleyebilirsiniz. Bu cevap ini_set ('hafıza_yükleme', '1024M'); Bunu kopyalayıp yapıştırabilir ve iyi olabilirsiniz. -1 olarak ayarlayarak, tüm belleği tüketen bir komut dosyasına sahip olacaksınız. Özellikle bunu rutin olarak yaparsanız. Tırnaklara "tehlikeli" koymak onu daha az tehlikeli yapmaz. Gerçekten sunucu sunucunuzu hortum olabilir. Belki de verileri yok etmeye başlayın. Bilmiyorum, belki işini kaybedersin? Kulağa oldukça tehlikeli geliyor. : |
Jeff Davis

3
+161 oy ve -3 oy için yanıtın aynı olduğunu görmek üzücü :(
akarthik10

130

Doğru yol, php.inidosyanızı düzenlemektir . Düzenleme memory_limitarzu değerine.

Sorunuzdan, 128M(varsayılan sınır olan) aşıldı, bu yüzden kodunuzda çok fazla yanlış olmaması gereken bir şey var.

Neden bu kadar uzun sürdüğünü ve ayarlanmasına memory_limit = 512Mveya daha yüksek olmasına izin vermek istiyorsanız ve iyi olmalısınız.


7
Dürüst olmak gerekirse, bazı ciddi miktarda veri önbelleğe alırsanız, bu doğru cevaptır. 128M, belirli komut dosyaları için yeterli değildir. 512M veya 1024M genellikle yeterli olacaktır, ancak duruma göre karar vermeniz gerekir.
Jeff Davis

2
Ancak, kullanıcı sayısı daha fazla olacaksa, büyük bellek kullanımından kaçınmaya çalışın
Basav

2
memory_limit = -1; php.ini içinde ayarlanır

2
@YumYumYum Bu, yalnızca bellek kullanımını başka bir şekilde izliyorsanız istediğiniz memory_limit öğesini kaldırır. İşletim sistemi, herhangi bir noktada çok fazla bellek alıyorsa işlemi öldürecektir.
Flimm

Bu nedenle, çok fazla bellek kullanan bir komut dosyası çalıştırıyorsanız, ancak yalnızca bir kez çalıştırmanız gerekiyorsa, yürütme sırasında işlem için bellek sınırını artırabilir, ardından bir kerelik süreden sonra bellek sınırınızı tekrar azaltabilirsiniz. script çalışır mı?
chromechris

95

PHP için bellek ayırma işlemi kalıcı olarak veya geçici olarak ayarlanabilir.

kalıcı olarak

PHP bellek tahsisini kalıcı olarak iki şekilde değiştirebilirsiniz.

php.iniDosyanıza erişiminiz varsa memory_limit, arzu ettiğiniz değerin değerini düzenleyebilirsiniz .

php.iniDosyanıza erişiminiz yoksa (ve web barındırıcınız izin veriyorsa), .htaccessdosya üzerinden bellek ayırmayı geçersiz kılabilirsiniz . Ekle php_value memory_limit 128M(veya istediğiniz ayırma ne olursa olsun).

Geçici

Bellek ayırmayı bir PHP dosyasından anında ayarlayabilirsiniz. Sadece kod ini_set('memory_limit', '128M');(veya istediğiniz tahsis ne olursa olsun) var. Değeri "-1" olarak ayarlayarak bellek sınırını kaldırabilirsiniz (makine veya örnek sınırları geçerli olsa da).


2
Teşekkürler Birisi php.ini geçersiz
kılınan

61

Bir PHP betiğinde bellek sızıntıları elde etmek çok kolaydır - özellikle ORM gibi bir soyutlama kullanıyorsanız. Betiğinizi profillemek ve tüm bu belleğin nereye gittiğini öğrenmek için Xdebug'u kullanmayı deneyin.


1
Ben Xdebug'u deneyeceğim. Daha önce hiç kullanmadım, bu yüzden okumak zorundayım. Yanıtladığınız için teşekkürler! Umarım bu sorunun cevabını yakında
buluruz

34
PHP'nin belleği yönetmek için referans sayımı kullandığını unutmayın. Dolayısıyla, döngüsel referanslarınız veya global değişkenleriniz varsa, bu nesneler geri dönüştürülmez. Bu genellikle PHP'deki bellek sızıntılarının köküdür.
troelskn

Xdebug, bellek sızıntısından CI'nin Xmlrpc.php kütüphanesinin sorumlu olduğunu gösteriyor. Şans eseri, CodeIgniter'in XML-RPC kitaplıklarıyla ilgili bilmem gereken herhangi bir sorun var mı? Tüm işleme sunucu tarafı devre dışı bırakmayı denedim ve yeterince veri beslerseniz hala bellek yetersiz.
ArcticZero

1
CI bilmiyorum / kullanıyorum, bu yüzden bilmiyorum. Ancak muhtemelen kullanımdan sonra serbest bırakılmamış bir nesne bulmaya çalışmalısınız - büyük olasılıkla döngüsel bir referans nedeniyle. Dedektiflik.
troelskn

1
Sorunun aslında ele alınmasını öneren tek cevap budur. Diğer cevaplar bir semptom üzerine bandaj yapmak ve hastalığı görmezden gelmek için hafızayı arttırır .
Chris Baker

56

Dizi_push ile bir diziye 22.5 milyon kayıt eklerken 4Gphp.ini dosyasında bellek sınırı olarak kullanarak yaklaşık 20M kayıtlarında "bellek tükenmiş" önemli hatalar almaya devam etti . Bunu düzeltmek için ifadeyi ekledim

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

tıklayın. Şimdi her şey yolunda gidiyor. PHP bir bellek sızıntısı olup olmadığını bilmiyorum. Bu benim işim değil, umrumda da değil. Sadece işimi halletmeliyim ve bu işe yaradı.

Program çok basit:

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

Ölümcül hata, hatayı ortadan kaldıran bellek sınırını artırana kadar 3. satırı gösteriyor.


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

2
Böyle bir şey için bir senaryoyu optimize etmek ve optimize etmek için zamana sahip olmak ne lüks. Ya da ETL araçlarını veya benzerlerini araştırın ve karşılaştırın ve öğrenin. Gerçek dünyada, bellek ödeneğini yukarı kaldırırız, işi yaparız ve devam ederiz.
Matthew Poer

45

Ben bile memory_limitayarlanmış php.inive bu değeri doğru okuma değeri ile bu hatayı almaya devam etti phpinfo().

Bunu bundan değiştirerek:

memory_limit=4G

Buna:

memory_limit=4096M

Bu PHP 7'deki sorunu düzeltti.


23

Yukarıdaki hatayı gördüğünüzde - özellikle (tried to allocate __ bytes)düşük bir değerse, bu, sonsuz bir döngünün göstergesi olabilir, örneğin, çıkış yolu olmadan kendini çağıran bir işlev gibi:

function exhaustYourBytes()
{
    return exhaustYourBytes();
}

19

Bu iki satırı etkinleştirdikten sonra çalışmaya başladı:

; 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

memory_limitFastcgi / fpm'yi değiştirerek bunu düzgün bir şekilde düzeltebilirsiniz :

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

128'den 512'ye kadar belleği değiştirin, aşağıya bakın

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

için

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

18

Sitenizin kök dizini:

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

1
bu benim için çalıştı. tek hat çözümlerini seviyorum. Kolaylık için +1
Steve C

14

Php.ini dosyasındaki bellek sınırını değiştirin ve Apache'yi yeniden başlatın. Yeniden başlattıktan sonra phpinfo (); herhangi bir PHP dosyasından bir memory_limitdeğişiklik onayı için işlev .

memory_limit = -1

Bellek sınırı -1, bellek sınırı ayarlanmadığı anlamına gelir. Şimdi maksimumda.


13

Drupal kullanıcıları için bu Chris Lane'nin yanıtı:

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

çalışıyor ama açıldıktan hemen sonra koymamız gerekiyor

<?php

sitenizin kök dizinindeki index.php dosyasında etiketleyin.


13

Drupal 7'de, sitelerinizdeki / varsayılan klasörünüzdeki settings.php dosyasındaki bellek sınırını değiştirebilirsiniz. 260. satır civarında şunu göreceksiniz:

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

Php.ini ayarlarınız yeterince yüksek olsa bile, Drupal settings.php dosyanızda ayarlanmadıysa 128 MB'den fazla tüketemezsiniz.


1
Drupal7'de değil, settings.php'de böyle bir kod dizesi yoktur
FLY

Ayrıca drupal 6 için settings.php de yoktur
AllisonC

12

Dosyanızdaki memory_limitdeğeri değiştirmek yerine php.ini, kodunuzun çok fazla bellek kullanabilen bir parçası varsa, memory_limito bölüm çalışmadan önce kaldırabilir ve sonra da değiştirebilirsiniz.

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

7

PHP 5.3+ .user.ini, public_htmlklasöre bir dosya yerleştirerek bellek sınırını değiştirmenizi sağlar . Sadece yukarıdaki dosyayı oluşturun ve içine aşağıdaki satırı yazın:

memory_limit = 64M

Bazı cPanel ana bilgisayarları yalnızca bu yöntemi kabul eder.


7

Sayfa kilitleniyor mu?

Resim açıklamasını buraya girin

(MySQL'in büyük satırları sorgulaması gerektiğinde olur. Varsayılan olarak, memory_limitdonanım için daha güvenli olan küçük olarak ayarlanır.)

Artırmadan önce sisteminizin mevcut bellek durumunu kontrol edebilirsiniz 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

Burada aşağıdaki gibi arttı ve sonra service httpd restartkilitlenme sayfası sorunu düzeltmek için yapmak .

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

free -mYeni bir memory_limit'e karar vermek için komutu çalıştırdıktan sonra hangi sayıya (satır ve sütun?) Bakılmalıdır?
kiradotee

7

ini_set('memory_limit', '-1');Web sayfanızın üstüne bir satır eklemeniz yeterlidir.

Ve hafızanızı -1, to 16M, vb. Yerine ihtiyacınıza göre ayarlayabilirsiniz .


6
Bu, mevcut birçok cevapla aynı şeyi söylüyor. Popüler bir soruya yalnızca yeni malzeme yeni bir şey sunuyorsa bir cevap eklemek en iyisidir.
halfer

6

Başlarını kaşıyanlar için, bu küçük fonksiyonun neden bir bellek sızıntısına neden olması gerektiğini bulmak için, bazen küçük bir hata ile, bir işlev sürekli olarak kendini çağırmaya başlar.

Örneğin, onu proxy yapacak nesnenin işlevi için aynı ada sahip bir proxy sınıfı.

class Proxy {

    private $actualObject;

    public function doSomething() {

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

Bazen o küçük actualObjec üyesini getirmeyi unutabilirsiniz ve proxy aslında bu doSomethingyönteme sahip olduğundan , PHP size herhangi bir hata vermez ve büyük bir sınıf için nedenini bulmak için birkaç dakika gözlerden gizlenebilir. bellek sızdırıyor.


Ve başka bir ipucu: die('here')kodunuzu girip özyinelemenin nerede başladığını görmek için bu ifadeyi hareket ettirebilirsiniz.
toddmo

6

Daha önce çalıştığından daha küçük bir veri kümesinde çalışırken aşağıdaki hatayı aldım.

Önemli hata: 173 satırındaki C: \ workspace \ image_management.php dosyasında izin verilen bellek boyutu 134217728 bayt tükendi (4096 bayt ayırmaya çalıştı)

Arıza arayışı beni buraya getirdiğinde, önceki cevaplardaki teknik çözümlerin her zaman değil, daha basit bir şeyden bahsettiğimi düşündüm. Benim durumumda bu Firefox'du. Programı çalıştırmadan önce zaten 1.157 MB kullanıyordu.

Görünüşe göre günler boyunca 50 dakikalık bir video izliyordum ve bu da işleri karıştırdı. Bu, uzmanların düşünmeden bile düzelttikleri bir tür düzeltmedir, ancak benim sevdiğim için akılda tutmaya değer.


Bugün Google Chrome'da benzer bir olay yaşadım. Bu yanıta son derece şüpheliydim ... ancak, gizli bir pencere açıp aynı senaryoyu tekrar ateşledikten sonra bayt bitimimin kaybolduğunu ortaya çıkardı! Araştırma devam ediyor.
mickmackusa

2

Komut dosyasını şu şekilde çalıştırmak (örneğin cron örneği): php5 /pathToScript/info.phpaynı hatayı üretir.

Doğru yol: php5 -cli /pathToScript/info.php


2

WHM destekli bir VPS (sanal özel sunucu) çalıştırıyorsanız, PHP.INI'yi doğrudan düzenleme izniniz olmadığını görebilirsiniz; sistem bunu yapmalıdır. WHM ana bilgisayar kontrol panelinde Hizmet YapılandırmasıPHP Yapılandırma Düzenleyicisi'ne gidin ve değiştirin memory_limit:

WHM 11.48.4'te memory_limit güncelleniyor


2

Başlığa dahil etmek yerine, gerçekte işlenen dosyaları dahil ederken veya gerektiğinde _dbconnection.php_ve yararlı bir _functions.phpdosyada buldum . Hangi kendi içine dahil.

Senin Yani başlık ve alt bilgi dahildir başlığı dahil edilmeden önce, basitçe tüm fonksiyonel dosyaları içerir.


2

Kullanmak yieldda bir çözüm olabilir. Bkz. Jeneratör sözdizimi .

Daha PHP.inibüyük bir bellek depolaması için dosyayı değiştirmek yerine , bazen yieldbir döngü içine uygulamak sorunu çözebilir. Verim, tüm verileri bir kerede boşaltmak yerine, teker teker okur ve çok fazla bellek kullanımını azaltır.


2
PHP.ini? Öyle değil mi php.ini?
Peter Mortensen

1

Bu hata bazen istisna işleme ve muhtemelen diğer işlemleri içeren özyinelemelere neden olan PHP kodundaki bir hatadan kaynaklanır. Ne yazık ki, küçük bir örnek oluşturamadım.

Benim için birkaç kez olan bu durumlarda set_time_limitbaşarısız olur ve tarayıcı sonsuz bir döngü veya bu sorunun konusu olan önemli hata mesajı ile PHP çıktısını yüklemeye çalışır.

Ekleyerek izin verilen ayırma boyutunu azaltarak

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

Kodunuzun başlangıcına yakın bir yerde ölümcül hatayı önleyebilmelisiniz.

O zaman sona eren, ancak hata ayıklamak zor bir program kalabilir.

Bu noktada BreakLoop(), kontrol kazanmak ve programınızdaki hangi döngü veya özyinelemenin soruna neden olduğunu bulmak için programınıza çağrılar ekleyin .

BreakLoop'un tanımı aşağıdaki gibidir:

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

$ LoopSite bağımsız değişkeni, kodunuzdaki bir işlevin adı olabilir. Gerçekten gerekli değildir, çünkü alacağınız hata mesajı sizi BreakLoop () çağrısını içeren satıra yönlendirecektir.


-1

Benim durumumda, bir fonksiyonun yazılma şekliyle ilgili kısa bir sorundu. Bir bellek sızıntısına, bir işlevin giriş değişkenine yeni bir değer atanması, örneğin:

/**
* 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

Aşağıdaki satırları kodumdan kaldırdığımda, hepsi iyi çalıştı!

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

Bu satırlar çalıştırdığım her dosyaya dahil edildi. Dosyaları tek tek çalıştırırken hepsi iyi çalıştı, ancak tüm dosyaları birlikte çalıştırırken bellek sızıntısı sorunu var. Her nasılsa "include_once" bir kez şeyler dahil değil, ya da ben yanlış bir şey yapıyorum ...


set_include_path(get_include_path() . get_include_path().'/phpseclib'); Bu, satırı içeren her dosya için '/ phpseclib' yolunu bir kez ekleyecektir ... böylece birçok kez ekleyebilir! Bir ayarlar dosyasına ve ayarlar dosyasına koymanızı öneririm include_once.
Farfromunique
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.