치명적인 오류 : 허용 된 메모리 크기 134217728 바이트 소진 (CodeIgniter + XML-RPC)


618

정기적으로 하나의 중앙 데이터베이스에 새로운 판매 데이터를 전송하는 보고서를 생성하기 위해 하나의 큰 데이터베이스에 데이터를 저장하는 많은 POS 시스템이 있습니다.

클라이언트 POS는 PHPPOS를 기반으로하며 표준 XML-RPC 라이브러리를 사용하여 판매 데이터를 서비스로 보내는 모듈을 구현했습니다. 서버 시스템은 CodeIgniter를 기반으로하며 웹 서비스 구성 요소에 XML-RPC 및 XML-RPCS 라이브러리를 사용합니다. 많은 판매 데이터를 보낼 때마다 (판매 테이블에서 50 행, 세일 내 각 항목과 관련된 sales_items의 개별 행) 다음과 같은 오류가 발생합니다.

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

의 기본값은 128M php.ini이지만 큰 숫자라고 가정합니다. 사실, 나는이 값을 1024M으로 설정하려고 시도했지만 오류가 발생하는 데 더 오랜 시간이 걸립니다.

내가 취한 단계에 관해서는 서버 측에서 모든 처리를 비활성화하려고 시도했으며 입력에 관계없이 미리 준비된 응답을 반환하도록 조작했습니다. 그러나 문제는 실제 데이터 전송에 있다고 생각합니다. PHP의 최대 스크립트 실행 시간을 비활성화하려고 시도했지만 여전히 오류가 발생합니다.


5
약간 혼란 스럽습니다 ... 클라이언트 또는 서버에서 오류가 발생하는 위치는 무엇입니까? 그리고 어느 단계에서 ... 클라이언트 전송, 서버 수신, 서버 처리, 서버 전송, 클라이언트 수신 또는 클라이언트 처리?
그렉

2
클라이언트 전송 또는 서버 수신 중에 오류가 발생하는 것 같습니다. 모든 서버 측 처리를 비활성화하고 전송 된 데이터에 관계없이 미리 준비된 응답을 보내도록 준비했습니다. 일정량의 데이터를 보내면 오류가 발생합니다. PHP.ini 설정을 변경하고 있습니다.
ArcticZero

42
메모리 제한은 128MB입니다 (두 번) :ini_set('memory_limit', '256M');

9
요약은 CodeIgniter를 Drupal과 혼동 한 사람들과 다른 사람들의 답변을 복사하여 붙여 넣은 사람들은 포인트를 얻기 위해 "누수를 그냥 무시하십시오"라는 답변을 모두 공감했습니다. 이 답변의 질은 어둡습니다.
Matti Virkkunen

답변:


697

memory_limitby를 변경하는 것은 올바른 해결책 ini_set('memory_limit', '-1');아닙니다 . 그렇게하지 마십시오.

PHP 코드에 어딘가에 메모리 누수가 발생할 수 있으며 서버가 원하는 모든 메모리를 사용하도록 지시합니다. 문제를 전혀 해결하지 않았을 것입니다. 서버를 모니터링하면 아마도 대부분의 RAM을 사용하고 디스크로 스왑하고 있음을 알 수 있습니다.

코드에서 문제가되는 코드를 추적하여 수정해야합니다.


173
@Jeff 당신은 아마 95 %의 시간 일 것입니다. 그러나 실제로 더 많은 메모리가 필요한 경우가 있습니다. 예를 들어, 앱이 처리하기 위해 대량의 데이터를 메모리에로드한다고 가정합니다 (예 : 15k 개의 구성 요소가 포함 된 BOM). 코드가 항상 버그 인 것은 아니며 때로는 약간 더 많은 메모리가 필요합니다 (예 : 128M 대신 256M). 그러나 나는 그것을 -1로 설정하는 것은 끔찍하게 나쁘다는 것에 동의합니다. 그러나 런타임시 합리적인 상황에 맞게 메모리 제한을 조정하는 것은 완벽하게 허용됩니다.
Pyrite

24
) @pyrite 그래 가끔 왜 안하지만 -1 프로세스가 더 많은 메모리가 필요하지만, 당신이 말한대로 256메가바이트 같은 몇 가지 논리적 인 양 메모리 제한을 증가시켜야하거나 512메가바이트 그 권리입니다
루카스 Lukac

9
@jeff 나는 그 가치가 개발 환경 에서만 테스트 목적으로 -1유용 할 수 있다고 전적으로 동의 합니다.
Esolitos

4
나머지 5 %의 이름을 지정한 경우 @Pyrite는 청크 단위로 데이터를 읽고 더 많은 메모리를 사용하는 대신 작업자를 사용하여 처리합니다. 데이터가 커지면 시간이 지남에 따라 점점 더 많은 메모리를 서버에 채우는 것을 제외 하고는이 솔루션도 확장되지만 제안은 작동하지 않습니다.
burzum

2
가장 일반적인 방법으로 ORM 에서이 문제는 PHP 메모리 제한이 훨씬 많은 모든 데이터를 가져 오려고 할 때 발생합니다. 예를 들어 월별 보고서를 생성하려고 할 때.
Stepchik

213

ini_set('memory_limit', '-1');기본 PHP 메모리 제한을 무시합니다 .


16
@williamcarswell; 이 문맥에서 -1PHP가 무제한 으로 이해하는 가치 입니다.
Alix Axel

7
@ ArseniuszŁozicki-서버 절약 할 수없는 리소스도 소비합니다 .
Ken Williams

124
이것이 너무 많은 공판을 얻는 것이 부끄러운 일입니다. php.ini 편집 또는 ini_set을 사용하여 정확한 값으로 설정하면 사람들이 더 많은 메모리가 필요할 때 완벽하게 유효한 솔루션입니다. 그것을 무제한으로 설정하는 것은 위험한 해킹입니다 :(
Jeff Davis

24
그런 다음 @ user1767586을 적절한 값으로 설정하십시오. 1024M으로 설정하여 스크립트가 오류를 발생시키지 못하게 할 수 있습니다. 이 답변이 말했다면 ini_set ( 'memory_limit', '1024M'); 복사하여 붙여 넣을 수 있습니다. -1로 설정하면 모든 메모리를 사용하는 스크립트를 갖도록 설정됩니다. 특히 당신이 이것을 일상적으로하는 경우에. 인용 부호에 "위험한"을 넣는 것이 덜 위험하지는 않습니다. 당신은 정말 호스트 서버를 호스 수 있습니다. 어쩌면 데이터 파괴를 시작할 수 있습니다. 잘 모르겠습니다. 직장을 잃을 수도 있습니까? 나에게는 꽤 위험한 것 같습니다. : |
Jeff Davis

3
+161 표와 -3 표에 대한 답변이 동일
하다는 것을 알고 슬프다

130

올바른 방법은 php.ini파일 을 편집하는 것 입니다. memory_limit원하는 가치로 편집 하십시오.

귀하의 질문에서 128M(기본 제한)이 초과되었으므로 코드에 그렇게 많이 들지 않아야하므로 코드에 심각한 문제가 있습니다.

왜 그렇게 많이 걸리는지 알고 그 memory_limit = 512M이상 을 허용하고 싶다면 좋을 것입니다.


7
솔직히, 많은 양의 데이터를 캐싱하는 경우 이것이 정답입니다. 128M은 특정 스크립트에 충분하지 않습니다. 512M 또는 1024M이면 충분하지만 경우에 따라 결정해야합니다.
Jeff Davis

2
그러나 Yeha는 사용자 수가 더 많아 질 경우 엄청난 메모리 사용을 피하려고 노력합니다.
Basav

2
memory_limit = -1; php.ini에서 설정

2
@YumYumYum 메모리 사용을 다른 방법으로 모니터링하는 경우에만 원하는 memory_limit를 제거합니다. 어느 시점에서 많은 양의 메모리를 사용하면 OS가 프로세스를 종료시킵니다.
Flimm

따라서 많은 메모리를 사용하는 스크립트를 실행하고 있지만 한 번만 실행하면 실행시 프로세스의 메모리 제한을 늘린 다음 일회성 후 메모리 제한을 다시 낮출 수 있습니다 스크립트가 실행됩니까?
chromechris

95

PHP의 메모리 할당은 영구적으로 또는 일시적으로 조정할 수 있습니다.

영구적으로

PHP 메모리 할당은 두 가지 방법으로 영구적으로 변경할 수 있습니다.

php.ini파일에 액세스 할 수 memory_limit있으면 원하는 값에 대한 값을 편집 할 수 있습니다 .

php.ini파일에 액세스 할 수없고 (웹 호스트가 허용하는 경우) .htaccess파일을 통해 메모리 할당을 무시할 수 있습니다 . 추가 php_value memory_limit 128M(또는 원하는 할당이 무엇이든).

일시적인

PHP 파일 내에서 즉시 메모리 할당을 조정할 수 있습니다. 당신은 단순히 코드 ini_set('memory_limit', '128M');(또는 원하는 할당이 무엇이든)를 가지고 있습니다. 값을 "-1"로 설정하여 메모리 제한을 제거 할 수 있습니다 (머신 또는 인스턴스 제한이 여전히 적용될 수 있음).


2
누군가가 php.ini를 재정의하는 .htaccess에 값을 설정했는지 확인하지 않았으며 +1
HostMyBus

61

특히 ORM과 같은 추상화를 사용하는 경우 PHP 스크립트에서 메모리 누수가 매우 쉽습니다. Xdebug를 사용하여 스크립트를 프로파일 링하고 모든 메모리가 어디로 갔는지 찾으십시오.


1
Xdebug를 사용해 보겠습니다. 나는 그것을 전에 사용한 적이 없으므로 그것을 읽어야합니다. 답장을 보내 주셔서 감사합니다! 내가 곧 이것에 대한 답을 찾을 수 있기를 바랍니다 ...
ArcticZero

34
PHP는 메모리 관리를 위해 참조 횟수를 사용합니다. 따라서 순환 참조 또는 전역 변수가 있으면 해당 객체는 재활용되지 않습니다. 그것은 일반적으로 PHP에서 메모리 누수의 근원입니다.
troelskn

Xdebug는 CI의 Xmlrpc.php 라이브러리가 메모리 누수를 담당 함을 보여줍니다. 우연히도 알아야 할 CodeIgniter의 XML-RPC 라이브러리에 문제가 있습니까? 모든 처리 서버 측을 비활성화하려고 시도했지만 충분한 데이터를 공급해도 여전히 메모리가 부족합니다.
ArcticZero

1
나는 CI를 모르거나 사용하기 때문에 모른다. 그러나 순환 참조로 인해 사용 후 해제되지 않은 객체를 찾으려고 시도해야합니다. 형사 일입니다.
troelskn

1
이것은 실제로 문제를 해결하도록 조언하는 유일한 대답입니다. 다른 답변은 증상 을 붕대 하고 질병을 무시 하기 위해 메모리를 크랭크 .
Chris Baker

56

array_push를 사용하여 2,250 만 개의 레코드를 배열에 추가 할 때 4Gphp.ini 파일의 메모리 제한으로 사용하여 약 20M 레코드에서 "메모리 소모"치명적 오류가 계속 발생했습니다 . 이 문제를 해결하기 위해 진술을 추가했습니다.

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

파일 상단에. 이제 모든 것이 잘 작동합니다. PHP에 메모리 누수가 있는지 모르겠습니다. 그건 내 일이 아니고 신경도 쓰지 않습니다. 나는 단지 내 일을 끝내야 만했다.

이 프로그램은 매우 간단합니다.

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

치명적 오류는 메모리 제한을 높일 때까지 3 행을 가리 키므로 오류가 제거되었습니다.


10
당신은 의미 ini_set('memory_limit', '8192M');합니까?
Gogol

2
그런 일을 위해 스크립트를 최적화하고 갈 시간이 있다면 얼마나 사치스러운 일입니까? 또는 ETL 도구 등을 연구하고 비교하고 배우십시오. 현실에서, 우리는 메모리 수당을 늘리고, 일을하고, 계속합니다.
Matthew Poer

45

memory_limit에서 설정 한 경우에도이 오류가 계속 발생 php.ini하고로 값을 올바르게 읽습니다 phpinfo().

이것을 다음과 같이 변경하면 :

memory_limit=4G

이에:

memory_limit=4096M

이것은 PHP 7의 문제를 해결했습니다.


23

위의 오류가 표시되면-특히 (tried to allocate __ bytes)값이 낮은 경우에는 무한 루프의 지표가 될 수 있습니다.

function exhaustYourBytes()
{
    return exhaustYourBytes();
}

19

이 두 줄을 활성화 한 후 작동하기 시작했습니다.

; 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 을 변경하여이 문제를 올바르게 해결할 수 있습니다 .

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

128에서 512로 메모리를 변경하십시오 (아래 참조).

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

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

18

사이트의 루트 디렉토리 :

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

1
이것은 나를 위해 일했습니다. 한 줄 솔루션을 좋아합니다. 단순성을 위해 +1
Steve C

14

php.ini 파일 에서 메모리 제한을 변경하고 Apache를 다시 시작하십시오. 다시 시작한 후 phpinfo ()를 실행하십시오 . memory_limit변경 확인을 위해 모든 PHP 파일에서 함수 .

memory_limit = -1

메모리 제한 -1은 메모리 제한이 설정되어 있지 않음을 의미합니다. 이제 최대입니다.


13

Drupal 사용자의 경우 Chris Lane의 답변은 다음과 같습니다.

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

작동하지만 개봉 직후에 넣어야합니다.

<?php

사이트의 루트 디렉토리에있는 index.php 파일에 태그를 추가하십시오.


13

Drupal 7에서는 sites / default 폴더에있는 settings.php 파일에서 메모리 제한을 수정할 수 있습니다. 260 라인 주위에 다음이 표시됩니다.

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

php.ini 설정이 충분히 높더라도 Drupal settings.php 파일에 설정되어 있지 않으면 128MB 이상을 사용할 수 없습니다.


1
Drupal7이 아닌 settings.php에는 그러한 코드 문자열이 없습니다.
FLY

drupal 6에 대한 settings.php에도 문자열이 없습니다
AllisonC

12

파일 의 memory_limit값을 변경하는 대신 php.ini많은 메모리를 사용할 수있는 코드 부분이있는 경우 memory_limit해당 섹션이 실행되기 전에를 제거한 다음 교체 할 수 있습니다.

$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_html. 위의 파일을 만들고 다음 줄을 입력하십시오.

memory_limit = 64M

일부 cPanel 호스트는이 방법 만 허용합니다.


7

충돌 페이지?

여기에 이미지 설명을 입력하십시오

(MySQL이 큰 행을 쿼리해야 할 때 발생합니다. 기본적 memory_limit으로 small로 설정되어 하드웨어에 더 안전합니다.)

다음을 늘리기 전에 시스템의 기존 메모리 상태를 확인할 수 있습니다 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

여기에서 다음과 같이 늘리고 service httpd restart충돌 페이지 문제를 해결합니다.

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

free -m새로운 memory_limit를 결정하기 위해 명령을 실행 한 후에는 어떤 숫자 (행과 열?)를보아야 합니까?
kiradotee

7

ini_set('memory_limit', '-1');웹 페이지 상단에 줄을 추가 하십시오.

그리고 -1, to 16M등 의 장소에서 필요에 따라 메모리를 설정할 수 있습니다 .


6
이것은 많은 기존 답변과 동일한 것을 말하는 것으로 보입니다. 새로운 자료가 새로운 것을 제공하는 경우에만 인기있는 질문에 대한 답변을 추가하는 것이 가장 좋습니다.
halfer

6

왜이 작은 기능으로 인해 메모리 누수가 발생해야 하는지를 알아 내기 위해 머리를 긁적 거리는 사람들을 위해, 때때로 약간의 실수로, 기능이 재귀 적으로 호출되기 시작합니다.

예를 들어 프록시 할 객체의 기능에 대해 동일한 이름을 가진 프록시 클래스가 있습니다.

class Proxy {

    private $actualObject;

    public function doSomething() {

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

때로는 실제 Objec 멤버를 가져 오는 것을 잊어 버릴 수도 있습니다. 프록시에는 실제로 해당 doSomething메소드 가 있기 때문에 PHP는 오류를주지 않으며 큰 클래스의 경우 몇 분 동안 눈에 숨겨져 이유를 알 수 있습니다 메모리 누수가 발생합니다.


또 다른 팁 : die('here')코드를 넣고 해당 문을 이동하여 재귀가 시작되는 위치를 볼 수 있습니다.
toddmo

6

이전에 작업했던 것보다 작은 데이터 세트에서 실행하는 동안 아래 오류가 발생했습니다.

치명적인 오류 : 173 행의 C : \ workspace \ image_management.php에서 134217728 바이트의 메모리 크기가 소진되었습니다 (4096 바이트를 할당하려고 시도했습니다).

결함에 대한 검색이 여기로 왔기 때문에 이전 답변의 기술 솔루션이 아니라 더 간단한 방법이라고 언급했습니다. 제 경우에는 Firefox였습니다. 프로그램을 실행하기 전에 이미 1,157MB를 사용하고있었습니다.

내가 며칠에 걸쳐 한 번에 50 분짜리 비디오를 조금보고 있었고 엉망이 된 것 같습니다. 전문가가 그것에 대해 생각조차하지 않고 수정하는 일종의 해결책이지만, 나 같은 사람에게는 염두에 둘 가치가 있습니다.


나는 오늘 구글 크롬에서도 비슷한 사건을 겪었다. 나는이 대답에 대해 회의적이었습니다 ... 그러나 시크릿 창을 열고 동일한 스크립트를 다시 시작한 후에 바이트 소진이 사라 졌다는 것을 알았습니다! 연구는 계속됩니다.
mickmackusa

2

다음과 같은 스크립트 실행 (예 : 크론 경우) : php5 /pathToScript/info.php 동일한 오류가 발생합니다.

올바른 방법 : php5 -cli /pathToScript/info.php


2

WHM 기반 VPS (가상 사설 서버)를 실행중인 경우 PHP.INI를 직접 편집 할 수있는 권한이 없습니다. 시스템이해야합니다. WHM 호스트 제어판에서 서비스 구성PHP 구성 편집기 로 이동하여 memory_limit다음을 수정하십시오 .

WHM 11.48.4에서 memory_limit 업데이트


2

포함하거나 요구할 때 유용 _dbconnection.php_하며_functions.php 실제로 오히려 헤더에 포함하여보다 처리되는 파일에. 그 자체가 포함되어 있습니다.

따라서 머리글바닥 글 이 포함되어 있으면 머리글이 포함되기 전에 모든 기능 파일을 포함하십시오.


2

사용 yield하는 것도 해결책 일 수 있습니다. 생성기 구문을 참조하십시오 .

PHP.ini더 큰 메모리 저장을 위해 파일을 변경하는 대신 yield내부 루프를 구현 하면 문제가 해결 될 수 있습니다. 수율은 모든 데이터를 한 번에 덤프하는 대신 하나씩 읽어서 많은 메모리 사용량을 절약합니다.


2
PHP.ini? 그렇지 php.ini않습니까?
피터 Mortensen

1

이 오류는 때때로 예외 처리 및 다른 작업과 관련된 재귀를 일으키는 PHP 코드의 버그로 인해 발생합니다. 불행히도, 나는 작은 예를 만들 수 없었습니다.

이런 경우에 여러 번 일어난 적이 있는데 set_time_limit 발생했지만 실패하고 브라우저는 무한 루프 또는이 질문의 주제 인 치명적인 오류 메시지로 PHP 출력을 계속로드하려고 시도합니다.

추가하여 허용 된 할당 크기를 줄임으로써

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

코드의 시작 부분 근처에서 치명적인 오류를 방지 할 수 있어야합니다.

그러면 종료되는 프로그램이 남아있을 수 있지만 여전히 디버그하기는 어렵습니다.

이 시점에서 BreakLoop()제어를 얻기 위해 프로그램 내부에 호출을 삽입 하여 프로그램의 루프 또는 재귀가 문제를 일으키는 원인을 찾으십시오.

BreakLoop의 정의는 다음과 같습니다.

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 인수는 코드에서 함수의 이름이 될 수 있습니다. 오류 메시지에 BreakLoop () 호출이 포함 된 행이 표시되므로 실제로는 필요하지 않습니다.


-1

필자의 경우 함수 작성 방법에 대한 간단한 문제였습니다. 함수의 입력 변수에 새로운 값을 할당하면 메모리 누수가 발생할 수 있습니다. 예 :

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

내 코드에서 다음 줄을 제거하면 모두 정상적으로 작동했습니다!

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

이 줄은 내가 실행중인 모든 파일에 포함되었습니다. 파일을 하나씩 실행할 때 모두 정상적으로 작동했지만 모든 파일을 함께 실행할 때 메모리 누수 문제가 발생했습니다. 어떻게 든 "include_once"에 일이 포함되어 있지 않거나 잘못된 일이 있습니다 ...


set_include_path(get_include_path() . get_include_path().'/phpseclib'); 줄이있는 각 파일에 대해 '/ phpseclib'경로를 한 번 추가합니다 ... 그래서 여러 번 추가 할 수 있습니다! 설정 파일과 설정 파일에 넣는 것이 좋습니다 include_once.
Farfromunique
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.