Errore irreversibile: dimensione della memoria consentita di 134217728 byte esauriti (CodeIgniter + XML-RPC)


619

Ho un sacco di sistemi client point of sale (POS) che inviano periodicamente nuovi dati di vendita a un database centralizzato, che memorizza i dati in un grande database per la generazione di report.

Il POS client si basa su PHPPOS e ho implementato un modulo che utilizza la libreria XML-RPC standard per inviare i dati di vendita al servizio. Il sistema server è basato su CodeIgniter e utilizza le librerie XML-RPC e XML-RPCS per il componente webservice. Ogni volta che invio molti dati sulle vendite (fino a 50 righe dalla tabella delle vendite e singole righe dagli articoli sales relativi a ciascun articolo all'interno della vendita) ricevo il seguente errore:

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

128M è il valore predefinito in php.ini, ma presumo che sia un numero enorme da interrompere. In effetti, ho anche provato a impostare questo valore su 1024M, e tutto ciò che serve è impiegare più tempo a errori.

Per quanto riguarda i passaggi che ho fatto, ho provato a disabilitare tutta l'elaborazione sul lato server e l'ho truccato per restituire una risposta predefinita indipendentemente dall'input. Tuttavia, credo che il problema risieda nell'effettivo invio dei dati. Ho anche provato a disabilitare il tempo massimo di esecuzione dello script per PHP, e continua a fuoriuscire.


5
Sono un po 'confuso ... dove si verifica l'errore - nel client o nel server? E in quale fase ... invio client, ricezione server, elaborazione server, invio server, ricezione client o elaborazione client?
Greg,

2
L'errore sembra verificarsi durante l'invio del client o la ricezione del server. Ho provato a disabilitare tutte le elaborazioni sul lato server e ad attrezzarle per inviare una risposta predefinita indipendentemente dai dati inviati. L'errore si verifica se invio oltre una determinata quantità di dati. Sto cambiando l'impostazione di PHP.ini.
ArcticZero,

42
il limite di memoria è di 128 MB, raddoppiarlo:ini_set('memory_limit', '256M');

9
Il sommario ha annullato tutte le risposte "ignora la fuga", persone che hanno confuso CodeIgniter con Drupal e persone che hanno semplicemente copiato e incollato le risposte di altre persone per ottenere punti. La qualità delle risposte in questo è spaventosa.
Matti Virkkunen,

Risposte:


697

Cambiare il memory_limitby nonini_set('memory_limit', '-1'); è una soluzione adeguata. Per favore, non farlo.

Il tuo codice PHP potrebbe avere una perdita di memoria da qualche parte e stai dicendo al server di usare solo tutta la memoria che desidera. Non avresti risolto il problema. Se monitori il tuo server, noterai che ora sta probabilmente utilizzando la maggior parte della RAM e addirittura scambiando su disco.

Probabilmente dovresti provare a rintracciare il codice offensivo nel tuo codice e risolverlo.


174
@Jeff, probabilmente hai ragione il 95% delle volte. Tuttavia, ci sono momenti in cui hai effettivamente bisogno di più memoria. Ad esempio, supponiamo che la tua app stia caricando un'enorme quantità di dati in memoria per l'elaborazione (diciamo una distinta base con 15k componenti). Non sempre il codice è difettoso, a volte basta solo un po 'più di memoria (ad es. 256 M anziché 128 M). Tuttavia, sono d'accordo che impostarlo su -1 è terribilmente negativo. Ma regolare il limite di memoria per situazioni ragionevoli in fase di esecuzione è perfettamente accettabile.
Pirite,

24
@pyrite sì, hai ragione nel dire che a volte un processo richiede più memoria, ma dovresti aumentare il limite di memoria ad una quantità logica come 256 MB come hai detto o 512 MB perché non MA -1;)
Lukas Lukac

9
@jeff Sono pienamente d'accordo, un valore di -1potrebbe essere utile solo negli ambienti di sviluppo per scopi di test.
Esolitos,

4
@Pyrite nei casi nominati per il restante 5% legge i dati in blocchi e usa un lavoratore per elaborarli invece di usare più memoria. Questa soluzione si ridimensionerà anche se il tuo suggerimento non funzionerà se non manterrai sempre più memoria nel tuo server nel tempo se i dati crescono.
burzum

2
Nel modo più comune questo problema in ORM quando si tenta di recuperare tutti i dati con un limite di memoria php molto maggiore. Ad esempio, quando si tenta di generare un report mensile.
Stepchik,

213

ini_set('memory_limit', '-1');ignora il limite di memoria PHP predefinito .


16
@williamcarswell; -1è un valore che PHP considera illimitato in questo contesto.
Alix Axel,

7
@ ArseniuszŁozicki: consumerà anche risorse che il server non può risparmiare.
Ken Williams,

124
Peccato che questo ottenga così tanti voti. Impostarlo su un valore preciso, con php.ini edits o ini_set, è una soluzione perfettamente valida quando le persone hanno bisogno di più memoria. Impostarlo su illimitato è un trucco pericoloso :(
Jeff Davis

24
@utente1767586 quindi impostarlo su un valore sano. È possibile impedire allo script di generare l'errore impostandolo su 1024M. Se questa risposta dicesse ini_set ('memory_limit', '1024M'); Puoi copiarlo e incollarlo. Impostandolo su -1 ti stai configurando per avere uno script che consuma tutta la memoria. Soprattutto se lo fai regolarmente. Mettere "pericoloso" tra virgolette non lo rende meno pericoloso. Potresti davvero manomettere il tuo server host. Forse iniziare a distruggere i dati. Non lo so, forse perderai il lavoro? Mi sembra abbastanza pericoloso. : |
Jeff Davis,

3
Triste nel vedere che la risposta per +161 voti e -3 voti è la stessa :(
akarthik10

130

Il modo corretto è modificare il tuo php.inifile. Modifica memory_limitsecondo il tuo valore desiderato.

A partire dalla tua domanda, 128M(che è il limite predefinito) è stato superato, quindi c'è qualcosa di gravemente sbagliato nel tuo codice in quanto non dovrebbe richiedere molto.

Se sai perché ci vuole così tanto e vuoi permetterlo impostato memory_limit = 512Mo superiore e dovresti essere buono.


7
Onestamente, se stai memorizzando nella cache alcune serie quantità di dati, questa è la risposta corretta. 128M non è sufficiente per alcuni script. 512M o 1024M saranno spesso sufficienti, ma devi decidere caso per caso.
Jeff Davis

2
Sì, tuttavia cerca di evitare un uso
eccessivo della

2
memory_limit = -1; impostato in php.ini

2
@YumYumYum Questo rimuove memory_limit, che desideri solo se stai monitorando l'utilizzo della memoria in altro modo. Il sistema operativo interromperà il processo se a un certo punto richiede un'enorme quantità di memoria.
Flimm,

Quindi, se stai eseguendo uno script che utilizza molta memoria, ma devi eseguirlo solo una volta, puoi semplicemente aumentare il limite di memoria per il processo al momento dell'esecuzione, quindi abbassare di nuovo il limite di memoria dopo il singolo l'esecuzione dello script?
chromechris,

95

L'allocazione di memoria per PHP può essere regolata permanentemente o temporaneamente.

Permanentemente

È possibile modificare in modo permanente l'allocazione della memoria PHP in due modi.

Se hai accesso al tuo php.inifile, puoi modificare il valore per memory_limitil valore desiderato.

Se non hai accesso al tuo php.inifile (e il tuo webhost lo consente), puoi sovrascrivere l'allocazione di memoria attraverso il tuo .htaccessfile. Aggiungi php_value memory_limit 128M(o qualunque sia l'allocazione desiderata).

Temporaneo

È possibile regolare l'allocazione di memoria al volo da un file PHP. Hai semplicemente il codice ini_set('memory_limit', '128M');(o qualunque sia l'allocazione desiderata). È possibile rimuovere il limite di memoria (sebbene i limiti della macchina o dell'istanza possano ancora essere applicati) impostando il valore su "-1".


2
Grazie non ho pensato di verificare se qualcuno avesse impostato il valore in .htaccess che stava scavalcando php.ini e non sono riuscito a capire perché +1
HostMyBus

61

È molto facile ottenere perdite di memoria in uno script PHP, specialmente se si utilizza l'astrazione, come un ORM. Prova a usare Xdebug per profilare il tuo script e scoprire dove è finita tutta quella memoria.


1
Vado a provare Xdebug. Non l'ho mai usato prima, quindi dovrò leggerlo. Grazie per avermi risposto! Spero di trovare presto la risposta a questa ...
ArcticZero,

34
Ricorda che PHP utilizza il conteggio dei riferimenti per la gestione della memoria. Quindi se hai riferimenti circolari o variabili globali, quegli oggetti non verranno riciclati. Di solito questa è la radice delle perdite di memoria in PHP.
troelskn,

Xdebug mostra che la libreria Xmlrpc.php di CI è responsabile della mia perdita di memoria. Per caso, ci sarebbero problemi con le librerie XML-RPC di CodeIgniter che dovrei conoscere? Ho provato a disabilitare tutta l'elaborazione sul lato server, e rimane ancora memoria insufficiente se fornisco dati sufficienti.
ArcticZero,

1
Non conosco / uso CI, quindi non lo so. Ma probabilmente dovresti provare a trovare un oggetto che non viene liberato dopo l'uso, molto probabilmente a causa di un riferimento ciclico. È un lavoro da investigatore.
troelskn,

1
Questa è l'unica risposta qui che consiglia effettivamente di affrontare il problema. Le altre risposte aumentano la memoria per fasciare un sintomo e ignorare la malattia .
Chris Baker,

56

Quando ho aggiunto 22,5 milioni di record in un array con array_push ho continuato a ricevere errori fatali "memoria esaurita" a circa 20 milioni di record usando 4Gcome limite di memoria nel file php.ini. Per risolvere questo problema, ho aggiunto la dichiarazione

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

nella parte superiore del file. Ora tutto funziona bene. Non so se PHP ha una perdita di memoria. Questo non è il mio lavoro, né me ne importa. Devo solo fare il mio lavoro e questo ha funzionato.

Il programma è molto semplice:

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

L'errore irreversibile punta alla riga 3 fino a quando non ho aumentato il limite di memoria, che ha eliminato l'errore.


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

2
Che lusso sarebbe avere il tempo di andare e ottimizzare una sceneggiatura per qualcosa del genere. Oppure cerca e confronta e apprendi gli strumenti ETL o alcuni di questi. Nel mondo reale, aumentiamo il margine di memoria, facciamo la cosa e andiamo avanti.
Matthew Poer,

45

Ho continuato a ricevere questo errore, anche con memory_limitset in php.ini, e il valore letto correttamente phpinfo().

Modificandolo da questo:

memory_limit=4G

A questo:

memory_limit=4096M

Questo ha risolto il problema in PHP 7.


23

Quando vedi l'errore sopra - specialmente se (tried to allocate __ bytes)è un valore basso, potrebbe essere un indicatore di un ciclo infinito, come una funzione che si chiama senza via d'uscita:

function exhaustYourBytes()
{
    return exhaustYourBytes();
}

19

Dopo aver abilitato queste due linee, ha iniziato a funzionare:

; 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

Puoi risolverlo correttamente cambiando memory_limitsu fastcgi / fpm:

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

Cambia memoria, come da 128 a 512, vedi sotto

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

per

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

18

Directory principale del tuo sito:

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

1
questo ha funzionato per me. amo le soluzioni a una linea. +1 per semplicità
Steve C

14

Modifica il limite di memoria nel file php.ini e riavvia Apache. Dopo il riavvio, eseguire phpinfo (); funzione da qualsiasi file PHP per una memory_limitconferma di modifica.

memory_limit = -1

Il limite di memoria -1 indica che non è stato impostato alcun limite di memoria. Adesso è al massimo.


13

Per gli utenti di Drupal, la risposta di Chris Lane a:

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

funziona ma dobbiamo metterlo subito dopo l'apertura

<?php

tag nel file index.php nella directory principale del tuo sito.


13

In Drupal 7, puoi modificare il limite di memoria nel file settings.php situato nella cartella siti / predefinita. Intorno alla linea 260, vedrai questo:

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

Anche se le tue impostazioni php.ini sono abbastanza alte, non sarai in grado di consumare più di 128 MB se questo non è impostato nel tuo file settings.php Drupal.


1
Non in Drupal7 non esiste una tale stringa di codice in settings.php
FLY il

Non c'è nemmeno una stringa in settings.php per drupal 6
AllisonC

12

Invece di modificare il memory_limitvalore nel tuo php.inifile, se c'è una parte del tuo codice che potrebbe usare molta memoria, puoi rimuovere memory_limitprima dell'esecuzione di quella sezione e poi sostituirla dopo.

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

7

PHP 5.3+ consente di modificare il limite di memoria inserendo un .user.inifile nella public_htmlcartella. Basta creare il file sopra e digitare la seguente riga in esso:

memory_limit = 64M

Alcuni host cPanel accettano solo questo metodo.


7

Pagina di arresto?

Inserisci qui la descrizione dell'immagine

(Succede quando MySQL deve interrogare file di grandi dimensioni. Per impostazione predefinita, memory_limit è impostato su piccolo, il che era più sicuro per l'hardware.)

È possibile controllare lo stato della memoria esistente del sistema, prima di aumentare 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

Qui l'ho aumentato come nel seguito e quindi faccio service httpd restartper risolvere il problema della pagina di arresto anomalo.

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

Quale numero (riga e colonna?) Si dovrebbe guardare dopo aver eseguito il free -mcomando per decidere un nuovo memory_limit?
Kiradotee,

7

Aggiungi una ini_set('memory_limit', '-1');riga nella parte superiore della tua pagina web.

E puoi impostare la tua memoria secondo le tue necessità al posto di -1, a 16M, ecc.


6
Questo sembra dire la stessa cosa di molte risposte esistenti. È meglio aggiungere una risposta a una domanda popolare solo se il nuovo materiale offre qualcosa di nuovo.
halfer

6

Per coloro che si grattano la testa per scoprire perché mai questa piccola funzione dovrebbe causare una perdita di memoria, a volte per un piccolo errore, una funzione inizia ricorsivamente chiamandosi per sempre.

Ad esempio, una classe proxy che ha lo stesso nome per una funzione dell'oggetto che sta per proxy.

class Proxy {

    private $actualObject;

    public function doSomething() {

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

A volte potresti dimenticare di portare quel piccolo membro effettivo di Objec e poiché il proxy ha effettivamente quel doSomethingmetodo, PHP non ti darebbe alcun errore e per una grande classe, potrebbe essere nascosto agli occhi per un paio di minuti per scoprire perché perde la memoria.


E un altro consiglio: puoi inserire il die('here')tuo codice e spostare quell'istruzione per vedere dove inizia la ricorsione.
toddmo,

6

Ho avuto l'errore di seguito durante l'esecuzione su un set di dati più piccolo di quanto avesse funzionato in precedenza.

Errore irreversibile: dimensione della memoria consentita di 134217728 byte esauriti (tentato di allocare 4096 byte) in C: \ workspace \ image_management.php sulla riga 173

Dato che la ricerca dell'errore mi ha portato qui, ho pensato di menzionare che non sono sempre le soluzioni tecniche nelle risposte precedenti, ma qualcosa di più semplice. Nel mio caso era Firefox. Prima di eseguire il programma utilizzava già 1.157 MB.

Si è scoperto che avevo guardato un video di 50 minuti un po 'alla volta per un periodo di giorni e questo ha rovinato le cose. È il tipo di correzione che gli esperti correggono senza nemmeno pensarci, ma per quelli come me vale la pena ricordare.


Oggi ho avuto un evento simile su Google Chrome. Ero estremamente scettico di questa risposta ... tuttavia, ha rivelato che la mia stanchezza di byte è scomparsa dopo aver aperto una finestra di navigazione in incognito e sparato di nuovo lo stesso script! La ricerca continua.
Mickmackusa,

2

Eseguendo lo script in questo modo (caso cron per esempio): php5 /pathToScript/info.phpproduce lo stesso errore.

Il modo corretto: php5 -cli /pathToScript/info.php


2

Se si esegue un VPS (server privato virtuale) basato su WHM, è possibile che non si disponga delle autorizzazioni per modificare direttamente PHP.INI; il sistema deve farlo. Nel pannello di controllo dell'host WHM, vai a Configurazione servizioEditor di configurazione PHP e modifica memory_limit:

Aggiornamento memory_limit su WHM 11.48.4


2

Lo trovo utile quando includo o richiedo _dbconnection.php_e _functions.phpnei file che vengono effettivamente elaborati, piuttosto che includere nell'intestazione. Che è incluso in sé.

Quindi, se l' intestazione e il piè di pagina sono inclusi, è sufficiente includere tutti i file funzionali prima di includere l'intestazione.


2

L'uso yieldpotrebbe anche essere una soluzione. Vedi Sintassi del generatore .

Invece di modificare il PHP.inifile per una memoria più grande, a volte l'implementazione di yieldun ciclo interno potrebbe risolvere il problema. Ciò che fa la resa è invece di scaricare tutti i dati in una volta, li legge uno per uno, risparmiando un sacco di utilizzo della memoria.


2
PHP.ini? No php.ini?
Peter Mortensen,

1

Questo errore è talvolta causato da un bug nel codice PHP che provoca ricorsioni che coinvolgono la gestione delle eccezioni e possibilmente altre operazioni. Sfortunatamente, non sono stato in grado di creare un piccolo esempio.

In questi casi, che sono accaduti più volte per me, set_time_limit , il browser continua a provare a caricare l'output di PHP, con un ciclo infinito o con il messaggio di errore fatale che è l'argomento di questa domanda.

Riducendo la dimensione di allocazione consentita aggiungendo

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

vicino all'inizio del codice dovresti essere in grado di prevenire l'errore fatale.

Quindi potresti rimanere con un programma che termina, ma è comunque difficile eseguire il debug.

A questo punto inserisci le BreakLoop()chiamate all'interno del tuo programma per ottenere il controllo e scoprire quale loop o ricorsione nel tuo programma sta causando il problema.

La definizione di BreakLoop è la seguente:

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

L'argomento $ LoopSite può essere il nome di una funzione nel tuo codice. Non è davvero necessario, poiché il messaggio di errore che riceverai ti indicherà la linea contenente la chiamata BreakLoop ().


-1

Nel mio caso è stato un breve problema con il modo in cui è stata scritta una funzione. Una perdita di memoria può essere causata assegnando un nuovo valore alla variabile di input di una funzione, ad esempio:

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

Quando ho rimosso le seguenti righe dal mio codice, tutto ha funzionato bene!

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

Queste righe sono state incluse in ogni file che stavo eseguendo. Quando eseguivo i file uno per uno, tutto funzionava bene, ma quando eseguivo tutti i file insieme ho avuto il problema di perdita di memoria. In qualche modo il "include_once" non include le cose una volta, o sto facendo qualcosa di sbagliato ...


set_include_path(get_include_path() . get_include_path().'/phpseclib'); Questo aggiungerà il percorso '/ phpseclib' una volta per ogni file che ha la linea ... quindi può aggiungerlo molte volte! Suggerirei di inserirlo in un file delle impostazioni e nel file include_oncedelle impostazioni.
Farfromunique,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.