Error fatal: tamaño de memoria permitido de 134217728 bytes agotados (CodeIgniter + XML-RPC)

619

Tengo un montón de sistemas de punto de venta (POS) de clientes que periódicamente envían nuevos datos de ventas a una base de datos centralizada, que almacena los datos en una gran base de datos para la generación de informes.

El POS del cliente se basa en PHPPOS, y he implementado un módulo que utiliza la biblioteca estándar XML-RPC para enviar datos de ventas al servicio. El sistema del servidor se basa en CodeIgniter y utiliza las bibliotecas XML-RPC y XML-RPCS para el componente de servicio web. Cada vez que envío una gran cantidad de datos de ventas (tan solo 50 filas de la tabla de ventas y filas individuales de artículos de ventas pertenecientes a cada artículo dentro de la venta) aparece el siguiente error:

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

128M es el valor predeterminado en php.ini, pero supongo que es un gran número para romper. De hecho, incluso he intentado establecer este valor en 1024M, y todo lo que hace es tomar más tiempo para error.

En cuanto a los pasos que he tomado, he intentado deshabilitar todo el procesamiento en el lado del servidor, y lo he manipulado para que devuelva una respuesta fija independientemente de la entrada. Sin embargo, creo que el problema radica en el envío real de los datos. Incluso he intentado deshabilitar el tiempo máximo de ejecución de script para PHP, y todavía se produce un error.

Ártico Cero
fuente
55
Estoy un poco confundido ... ¿dónde se produce el error, en el cliente o servidor? ¿Y en qué etapa ... envío del cliente, recepción del servidor, procesamiento del servidor, envío del servidor, recepción del cliente o procesamiento del cliente?
Greg
2
El error parece ocurrir durante el envío del cliente o la recepción del servidor. He intentado deshabilitar todo el procesamiento en el servidor y manipularlo para enviar una respuesta enlatada independientemente de los datos enviados. El error ocurre si envío una cierta cantidad de datos. Estoy cambiando la configuración de PHP.ini.
ArcticZero
42
el límite de memoria es de 128 MB, duplíquelo:ini_set('memory_limit', '256M');
99
Resumen rechazó todas las respuestas de "ignorar la filtración", las personas que confundieron CodeIgniter con Drupal y las personas que simplemente copiaron y pegaron las respuestas de otras personas para obtener puntos. La calidad de las respuestas en este caso es abismal.
Matti Virkkunen

Respuestas:

697

Cambiar el memory_limitby noini_set('memory_limit', '-1'); es una solución adecuada. Por favor no hagas eso.

Su código PHP puede tener una pérdida de memoria en algún lugar y le está diciendo al servidor que use toda la memoria que quiera. No habrías solucionado el problema en absoluto. Si monitorea su servidor, verá que ahora probablemente está utilizando la mayor parte de la RAM e incluso está cambiando al disco.

Probablemente debería intentar localizar el código ofensivo en su código y corregirlo.

Jeff
fuente
174
@Jeff, probablemente tengas razón el 95% del tiempo. Sin embargo, hay momentos en los que realmente necesita más memoria. Por ejemplo, supongamos que su aplicación está cargando una gran cantidad de datos en la memoria para su procesamiento (por ejemplo, una lista de materiales con 15 mil componentes). No siempre es el caso de que el código tenga errores, a veces solo necesita un poco más de memoria (por ejemplo, 256M en lugar de 128M). Sin embargo, estoy de acuerdo en que establecerlo en -1 es terriblemente malo. Pero ajustar el límite de memoria para situaciones razonables en tiempo de ejecución es perfectamente aceptable.
Pirita
24
@pyrite sí, tienes razón en que a veces un proceso requiere más memoria, pero debes aumentar el límite de memoria a una cantidad lógica como 256 MB como dijiste o 512 MB por qué no PERO no -1;)
Lukas Lukac
99
@jeff Estoy totalmente de acuerdo, un valor de -1podría ser útil solo en entornos de desarrollo para fines de prueba.
Esolitos
44
@Pyrite en los casos que nombró para el 5% restante, lea los datos en fragmentos y use un trabajador para procesarlos en lugar de usar más memoria. Esta solución también se ampliará, mientras que su sugerencia no funcionará, excepto que siga acumulando más y más memoria en su servidor con el tiempo si los datos crecen.
burzum
2
De la manera más común, este problema en ORM cuando intenta obtener todos los datos tiene un límite de memoria mucho más php. Por ejemplo, cuando intentas generar un informe mensual.
Stepchik
213

ini_set('memory_limit', '-1');anula el límite de memoria PHP predeterminado .

Chris Lane
fuente
16
@williamcarswell; -1es un valor que PHP entiende como ilimitado en este contexto.
Alix Axel
77
@ ArseniuszŁozicki: también consumirá recursos que el servidor no puede ahorrar.
Ken Williams
124
Es una pena que esto reciba tantos votos positivos. Establecerlo en un valor preciso, con ediciones php.ini o ini_set, es una solución perfectamente válida cuando las personas necesitan más memoria. Establecerlo como ilimitado es un truco peligroso :(
Jeff Davis
24
@ user1767586 luego configúrelo en un valor razonable. Puede evitar que el script arroje el error configurándolo en 1024M. Si esta respuesta dice ini_set ('memory_limit', '1024M'); Podrías copiar y pegar eso y estar bien. Al establecerlo en -1, se está configurando para tener un script que consume toda la memoria. Especialmente si haces esto rutinariamente. Poner "peligroso" entre comillas no lo hace menos peligroso. Realmente podrías controlar tu servidor host. Tal vez comience a destruir datos. No sé, ¿tal vez pierdas tu trabajo? Suena bastante peligroso para mí. : |
Jeff Davis
3
Es triste ver que la respuesta para +161 votos y -3 votos es la misma :(
akarthik10
130

La forma correcta es editar su php.iniarchivo. Edite memory_limita su valor deseado.

A partir de su pregunta, 128M(que es el límite predeterminado) se ha excedido, por lo que hay algo muy mal con su código, ya que no debería tomar tanto.

Si sabe por qué se necesita tanto y desea permitir que se establezca memory_limit = 512Mo más, debería ser bueno.

Basav
fuente
77
Honestamente, si está almacenando en caché grandes cantidades de datos, esta es la respuesta correcta. 128M no es suficiente para ciertos scripts. 512M o 1024M a menudo serán suficientes, pero debe decidir caso por caso.
Jeff Davis
2
Yeha, sin embargo, tratar de evitar el uso de memoria enorme, si el número de usuarios va a ser más
Basav
2
memoria_limit = -1; establecido en php.ini
2
@YumYumYum Eso elimina el límite de memoria, que solo desea si está monitoreando el uso de la memoria de otra manera. El sistema operativo matará el proceso si está tomando una gran cantidad de memoria en algún momento de alguna manera.
Flimm
Entonces, si está ejecutando un script que usa mucha memoria, pero solo necesita ejecutarlo una vez, ¿puede simplemente aumentar el límite de memoria para el proceso en el momento de la ejecución, y luego volver a bajar el límite de memoria después de su única vez? script ejecuta?
Chromerome
95

La asignación de memoria para PHP se puede ajustar de forma permanente o temporal.

Permanentemente

Puede cambiar permanentemente la asignación de memoria PHP de dos maneras.

Si tiene acceso a su php.iniarchivo, puede editar el valor memory_limita su valor deseado.

Si no tiene acceso a su php.iniarchivo (y su webhost lo permite), puede anular la asignación de memoria a través de su .htaccessarchivo. Agregar php_value memory_limit 128M(o lo que sea su asignación deseada).

Temporal

Puede ajustar la asignación de memoria sobre la marcha desde un archivo PHP. Simplemente tiene el código ini_set('memory_limit', '128M');(o la asignación que desee). Puede eliminar el límite de memoria (aunque todavía pueden aplicarse límites de máquina o instancia) estableciendo el valor en "-1".

Idrees de Umair
fuente
2
Gracias. No pensé en verificar si alguien había establecido el valor en .htaccess, que estaba anulando php.ini y no podía entender por qué +1
HostMyBus
61

Es muy fácil obtener pérdidas de memoria en un script PHP, especialmente si usa abstracción, como un ORM. Intente usar Xdebug para perfilar su secuencia de comandos y averiguar dónde se fue toda esa memoria.

troelskn
fuente
1
Iré a probar Xdebug. Nunca lo he usado antes, así que tendré que leerlo. ¡Gracias por responder! Espero encontrar la respuesta a esto pronto ...
ArcticZero
34
Recuerde que PHP usa el recuento de referencias para administrar la memoria. Entonces, si tiene referencias circulares o variables globales, esos objetos no se reciclarán. Esa suele ser la raíz de las pérdidas de memoria en PHP.
troelskn
Xdebug muestra que la biblioteca Xmlrpc.php de CI es responsable de mi pérdida de memoria. Por casualidad, ¿habría algún problema con las bibliotecas XML-RPC de CodeIgniter que debería conocer? He intentado deshabilitar todo el procesamiento del lado del servidor, y todavía se queda sin memoria si le doy suficientes datos.
ArcticZero
1
No sé / uso CI, así que no sé. Pero probablemente debería intentar encontrar un objeto que no se libere después del uso, muy probablemente debido a una referencia cíclica. Es trabajo de detective.
troelskn
1
Esta es la única respuesta aquí que aconseja realmente abordar el problema. Las otras respuestas aumentan la memoria para vendar un síntoma e ignoran la enfermedad .
Chris Baker
56

Cuando agregué 22.5 millones de registros en una matriz con array_push, seguía recibiendo errores fatales de "memoria agotada" en alrededor de 20 millones de registros usando 4Gcomo límite de memoria en el archivo php.ini. Para solucionar esto, agregué la declaración

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

en la parte superior del archivo. Ahora todo está funcionando bien. No sé si PHP tiene una pérdida de memoria. Ese no es mi trabajo, ni me importa. Solo tengo que hacer mi trabajo, y esto funcionó.

El programa es muy simple:

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

El error fatal apunta a la línea 3 hasta que aumenté el límite de memoria, lo que eliminó el error.

JamesAD-0
fuente
10
quieres decir ini_set('memory_limit', '8192M');?
Gogol
2
Qué lujo sería tener tiempo para ir y optimizar un script para algo así. O investigue y compare y aprenda herramientas ETL o algo así. En el mundo real, aumentamos la asignación de memoria, hacemos las cosas y seguimos adelante.
Matthew Poer
45

Seguí recibiendo este error, incluso con memory_limitset in php.ini, y el valor se lee correctamente con phpinfo().

Al cambiarlo de esto:

memory_limit=4G

A esto:

memory_limit=4096M

Esto rectificó el problema en PHP 7.

Danny Beckett
fuente
23

Cuando vea el error anterior, especialmente si (tried to allocate __ bytes)es un valor bajo, eso podría ser un indicador de un bucle infinito, como una función que se llama a sí misma sin salida:

function exhaustYourBytes()
{
    return exhaustYourBytes();
}
Kristen Waite
fuente
19

Después de habilitar estas dos líneas, comenzó a funcionar:

; 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

Prem Kumar Maurya
fuente
19

Puede corregir esto correctamente cambiando memory_limitfastcgi / fpm:

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

Cambiar la memoria, como de 128 a 512, ver abajo

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

a

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

El directorio raíz de su sitio:

ini_set('memory_limit', '1024M');
Gaurang P
fuente
1
Esto funcionó para mí. Amo las soluciones de una línea. +1 por simplicidad
Steve C
14

Cambie el límite de memoria en el archivo php.ini y reinicie Apache. Después del reinicio, ejecute phpinfo (); funcionar desde cualquier archivo PHP para una memory_limitconfirmación de cambio.

memory_limit = -1

El límite de memoria -1 significa que no hay un límite de memoria establecido. Ahora está al máximo.

Hasib Kamal
fuente
13

Para los usuarios de Drupal, la respuesta de Chris Lane de:

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

funciona pero necesitamos ponerlo justo después de la apertura

<?php

etiqueta en el archivo index.php en el directorio raíz de tu sitio.

sigmapi13
fuente
13

En Drupal 7, puede modificar el límite de memoria en el archivo settings.php ubicado en su sitio / carpeta predeterminada. Alrededor de la línea 260, verá esto:

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

Incluso si su configuración de php.ini es lo suficientemente alta, no podrá consumir más de 128 MB si no está configurada en su archivo Drupal settings.php.

LK7889
fuente
1
No en Drupal7 no hay una cadena de código de este tipo en settings.php
FLY
Tampoco hay una cadena en settings.php para drupal 6
AllisonC
12

En lugar de cambiar el memory_limitvalor en su php.iniarchivo, si hay una parte de su código que podría usar mucha memoria, podría eliminar el memory_limitantes de que se ejecute esa sección y luego reemplazarlo después.

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

PHP 5.3+ le permite cambiar el límite de memoria colocando un .user.iniarchivo en la public_htmlcarpeta. Simplemente cree el archivo anterior y escriba la siguiente línea:

memory_limit = 64M

Algunos hosts cPanel solo aceptan este método.

Sabi
fuente
7

¿Página de bloqueo?

Ingrese la descripción de la imagen aquí

(Ocurre cuando MySQL tiene que consultar filas grandes. De manera predeterminada, memory_limitestá configurado en pequeño, lo que era más seguro para el hardware).

Puede verificar el estado de la memoria existente de su sistema, antes de aumentar 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

Aquí lo he aumentado como en el siguiente y luego hago service httpd restartpara solucionar el problema de la página de bloqueo.

# grep memory_limit /etc/php.ini
memory_limit = 512M
Peter Mortensen
fuente
¿Qué número (fila y columna?) Se debe mirar después de ejecutar el free -mcomando para decidir sobre un nuevo memory_limit?
kiradotee
7

Simplemente agregue una ini_set('memory_limit', '-1');línea en la parte superior de su página web.

Y puede configurar su memoria según sus necesidades en lugar de -1, a 16M, etc.

Pankaj Pratik Rai
fuente
66
Esto parece decir lo mismo que muchas respuestas existentes. Lo mejor es agregar una respuesta a una pregunta popular solo si el nuevo material ofrece algo novedoso.
halfer
6

Para aquellos que se rascan la cabeza para descubrir por qué demonios esta pequeña función debería causar una pérdida de memoria, a veces por un pequeño error, una función comienza a llamarse recursivamente para siempre.

Por ejemplo, una clase proxy que tiene el mismo nombre para una función del objeto que lo va a proxy.

class Proxy {

    private $actualObject;

    public function doSomething() {

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

A veces puede olvidarse de traer ese pequeño miembro actual de Objec y debido a que el proxy realmente tiene ese doSomethingmétodo, PHP no le daría ningún error y, para una clase grande, podría ocultarse de los ojos durante un par de minutos para descubrir por qué está goteando el recuerdo.

madz
fuente
Y otro consejo: puede poner die('here')su código y mover esa declaración para ver dónde comienza la recursividad.
toddmo
6

Tuve el siguiente error al ejecutar un conjunto de datos más pequeño que el que había trabajado anteriormente.

Error fatal: tamaño de memoria permitido de 134217728 bytes agotados (intentó asignar 4096 bytes) en C: \ workspace \ image_management.php en la línea 173

Como la búsqueda de la falla me trajo aquí, pensé en mencionar que no siempre son las soluciones técnicas en las respuestas anteriores, sino algo más simple. En mi caso fue Firefox. Antes de ejecutar el programa, ya estaba usando 1,157 MB.

Resulta que había estado viendo un video de 50 minutos un poco a la vez durante un período de días y eso arruinó las cosas. Es el tipo de solución que los expertos corrigen sin siquiera pensarlo, pero vale la pena tenerlo en cuenta para mí.

M61Vulcan
fuente
Tuve una ocurrencia similar en Google Chrome hoy. Estaba extremadamente escéptico de esta respuesta ... sin embargo, ¡reveló que mi agotamiento de bytes desapareció después de abrir una ventana de incógnito y disparar el mismo guión nuevamente! La investigación continúa.
mickmackusa
2

Ejecutar el script de esta manera (caso cron, por ejemplo): php5 /pathToScript/info.phpproduce el mismo error.

La forma correcta: php5 -cli /pathToScript/info.php

ratm
fuente
2

Si está ejecutando un VPS (servidor privado virtual) con WHM, es posible que no tenga permisos para editar PHP.INI directamente; El sistema debe hacerlo. En el panel de control del host WHM, vaya a Configuración de servicioEditor de configuración PHP y modifique memory_limit:

Actualización de memory_limit en WHM 11.48.4

Janckos
fuente
2

Me resulta útil al incluir o requerir _dbconnection.php_y _functions.phpen archivos que realmente se procesan, en lugar de incluir en el encabezado. Que está incluido en sí mismo.

Entonces, si su encabezado y pie de página están incluidos, simplemente incluya todos sus archivos funcionales antes de incluir el encabezado.

Kerim
fuente
2

Usar también yieldpodría ser una solución. Ver sintaxis del generador .

En lugar de cambiar el PHP.iniarchivo por un almacenamiento de memoria más grande, a veces implementar yieldun bucle interno puede solucionar el problema. Lo que hace el rendimiento es que, en lugar de descargar todos los datos a la vez, los lee uno por uno, ahorrando mucho uso de memoria.

LukeDS
fuente
2
PHP.ini? ¿No es así php.ini?
Peter Mortensen
1

Este error a veces es causado por un error en el código PHP que causa recurrencias que involucran manejo de excepciones y posiblemente otras operaciones. Desafortunadamente, no he podido crear un pequeño ejemplo.

En estos casos, que me han sucedido varias veces, set_time_limitfalla y el navegador sigue intentando cargar la salida de PHP, ya sea con un bucle infinito o con el mensaje de error fatal que es el tema de esta pregunta.

Al reducir el tamaño de asignación permitido agregando

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

cerca del comienzo de su código, debería poder evitar el error fatal.

Entonces es posible que se quede con un programa que finaliza, pero aún es difícil de depurar.

En este punto, inserte BreakLoop()llamadas dentro de su programa para obtener el control y averiguar qué bucle o recursión en su programa está causando el problema.

La definición de BreakLoop es la siguiente:

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

El argumento $ LoopSite puede ser el nombre de una función en su código. No es realmente necesario, ya que el mensaje de error que recibirá lo dirigirá a la línea que contiene la llamada BreakLoop ().

David Spector
fuente
-1

En mi caso, fue un breve problema con la forma en que se escribió una función. Se puede causar una pérdida de memoria al asignar un nuevo valor a la variable de entrada de una función, por ejemplo:

/**
* 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';
}
Dmitriy Kravchuk
fuente
-6

Cuando eliminé las siguientes líneas de mi código, ¡todo funcionó bien!

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

Estas líneas se incluyeron en cada archivo que estaba ejecutando. Cuando ejecuté los archivos uno por uno, todo funcionó bien, pero cuando ejecuté todos los archivos juntos tuve el problema de pérdida de memoria. De alguna manera, "include_once" no incluye cosas una vez, o estoy haciendo algo mal ...

Omar Al-Azzawi
fuente
set_include_path(get_include_path() . get_include_path().'/phpseclib'); Esto agregará la ruta '/ phpseclib' una vez para cada archivo que tenga la línea ... ¡para que pueda agregarla muchas veces! Sugeriría ponerlo en un archivo de configuración y include_onceel archivo de configuración.
Farfromunique