2011-06-13 7 views
24

높이 배열 인 1024x1024 크기의 배열로 작업하고 있는데 메모리 제한이 있습니다. 내 테스트 머신에서 내가 원한다면 1GB로 mem 한계를 늘릴 수 있지만, 단지 256 램을 가진 나의 작은 VPS에서는 옵션이 아닙니다.PHP 배열의 메모리 최적화

저는 스택과 구글을 검색해 보았습니다. "메모리 효율, 도랑 및 C++로 다시 작성하기 때문에 PHP를 사용하지 않고 있습니다."라고 솔직히 말해서, 저는 PHP가 메모리를 좋아한다는 것을 알고 있습니다.

그러나 PHP 메모리 관리를 더 많이 조사 할 때 모든 데이터 유형을 소비하는 메모리를 찾지 못했습니다. 또는 다른 유형의 데이터로 변환하면 mem 소비가 줄어 듭니다.

"최적화"기술은 변수와 배열을 설정 해제 한 것뿐입니다.

일부 PHP 파서를 사용하여 코드를 C++로 변환하면 문제가 해결됩니까?

감사합니다.

+3

배열은 실제로 PHP에서 메모리가 많이 필요합니다 (실제로는 사전이므로). 만약 당신이 몇 가지 (많은!) 속도를 포기할 수 있습니다 [C와 같은 이진 배열을 가짜 수 있습니다] (http://stackoverflow.com/questions/5505124/cheating-php-integers/5505643#5505643), 또한 2D 구조 그렇 겠지. 하지만 어쩌면 당신은 정말로 [HipHop PHP to C++ 컴파일러] (https://github.com/facebook/hiphop-php/wiki/)를 조사하고 싶을 것입니다. – mario

+0

PHP의 모든 변수에는 이와 관련된 오버 헤드가 있습니다. 변수의 값을 저장해야 할뿐만 아니라 변수의 이름, 유형 등을 저장해야 할뿐만 아니라 간단한'$ x [1] = 2; '라고해도 큰 따옴표가 있습니다. –

+0

PHP 확장 기능은 무엇입니까? – Bytemain

답변

44

실제 인덱싱 된 배열을 원하면 SplFixedArray을 사용하십시오. 더 적은 메모리를 사용합니다. 또한 PHP 5.3에는 더 나은 가비지 수집기가 있습니다.

그 외에도 PHP는보다 신중하게 작성된 C/C++ 코드보다 많은 메모리를 사용합니다.

메모리 사용량 1024 × 1024의 정수 어레이 :

  • 표준 배열 : 218,756,848
  • SplFixedArray : 92,914,208

memory_get_peak_usage()

$array = new SplFixedArray(1024 * 1024); // array(); 
for ($i = 0; $i < 1024 * 1024; ++$i) 
    $array[$i] = 0; 

echo memory_get_peak_usage(); 

참고로 측정 한 것과 같은 배열 64 비트 정수를 사용하는 C는 8M이됩니다.

다른 사람들이 제안했듯이 데이터를 문자열로 묶을 수 있습니다. 이 속도는 더 느리지 만 훨씬 더 많은 메모리가 효율적입니다. 8 개 비트 값을 사용하는 경우가 매우 쉽다 :

$x = str_repeat(chr(0), 1024*1024); 
$x[$i] = chr($v & 0xff); // store value $v into $x[$i] 
$v = ord($x[$i]);  // get value $v from $x[$i] 

여기서 메모리에만 1.5MB 관한 것이다 (다만,이 정수 문자열 배열 PHP의 전체 오버 헤드를 고려할 때).

재미있게하기 위해 1024x1024 8 비트 정수를 만든 다음이를 한 번 반복하는 간단한 벤치 마크를 만들었습니다. 팩 버전은 모두 ArrayAccess을 사용하여 사용자 코드가 동일하게 보입니다.

    mem write read 
array    218M 0.589s 0.176s 
packed array  32.7M 1.85s 1.13s 
packed spl array 13.8M 1.91s 1.18s 
packed string  1.72M 1.11s 1.08s 

포장 된 배열 (서명 된 데이터를 처리 방지하기 위해 7 바이트 포장) 기본 64 비트 정수를 사용하여 압축 문자열은 ordchr을 사용했다. 분명히 구현 세부 사항과 컴퓨터 사양은 약간의 것들에 영향을 미치지 만 비슷한 결과를 기대합니다.

배열이 6 배 빨라지면서 다음 최상의 대안으로 125x 메모리를 사용했습니다. 당신이 기억이 부족하다면 분명히 속도는 무의미하다. (ArrayAccess 클래스없이 직접 팩 문자열을 사용한 경우 기본 배열보다 3 배 느렸다.)

간단히 요약하자면, 속도가 걱정된다면이 데이터를 처리하기 위해 순수 PHP 이외의 것을 사용할 것입니다.

+0

+1 또한 배열 인덱스를 에뮬레이트하고 패킹을 사용하면 적용 가능한 경우 메모리 사용량을 더 줄일 수 있습니다. 예 : 각 높이 맵 값이 8 비트 인 경우 * 메모리 사용량은 32 비트 (또는 PHP 비트 니스에 따라 64 비트)로 압축 될 때 상당히 적습니다. 효율성의 정확한 증가는 페이로드 크기/사용률 대 사용 된 PHP 값의 가치 유지 관리 오버 헤드로 인해 다릅니다. (정수 값 당 "오버 헤드"의 4 바이트가 있다고 생각하지만 완전히 확신하지는 않습니다.) –

+0

분명히 4 바이트 이상의 오버 헤드가 있습니다 ... [이 게시물] (http://stackoverflow.com/questions/5972170/what-of-the-the-the-of-the-of-the-of-php-int)는 사소한 값에 대해서 36 바이트 (또는 x64의 경우 72 바이트)를 넘을 수 있다고 제안합니다. 이것은 팩에 대해 (메모리 사용면에서) 매우 유익하다는 것을 나타냅니다. 8 비트 입력과 32 비트 아치를 가정 할 때, x64 컴퓨터에서 패킹하는 경우 4 개 값은 ~ 36 바이트 대 ~ 144 바이트가 걸릴 것입니다. 8 값은 ~ 576 바이트 대 ~ 72 바이트가 걸릴 것입니다! (Yikes!) –

+0

결론적으로, 패킹의 경우, 어레이 자체에 포함하기 위해 필요한 메모리를 제외하고 9MB의 오브젝트 오버 헤드/데이터의 오프 - 커프 추정을 위해 8 비트 값을 ~ 9 바이트로 상각하고, 등등 - 분기 된 숫자는 총 사용량이 ~ 22.5MB입니다. (그러한 패킹은 지나치게 최적화 된 것처럼 보일 수 있지만, 대상은 256MB RAM으로 제한되어 있다고 생각합니다. ;-) –

11

의견에 허용되는 답변과 제안 외에도 PHP Judy array implementation을 제안하고자합니다.

빠른 테스트 결과 흥미로운 결과가 나타났습니다. 일반적인 PHP 배열 데이터 구조를 사용하는 1 백만 개의 항목을 가진 배열은 ~ 200 MB를 필요로합니다. SplFixedArray는 약 90 메가 바이트를 사용합니다. Judy는 8 메가를 사용합니다. 절충안은 성능면에서, Judy는 정규 php 배열 구현 시간의 두 배 정도 걸립니다.

+0

아, 잘 지내요! 내 경우에는 램을 구하기 위해 성능이 저하 될 수 있습니다. –

+0

정확히 내가 필요한 것! [Judy Array] (http://en.wikipedia.org/wiki/Judy_array)는 대단합니다. 고성능 및 낮은 메모리 사용. – FlycKER

+0

@FlycKER - 누군가가이 멋진 배열 구현을 사용하기로 결정한 것을 기쁘게 생각합니다 :) –