2015-01-11 3 views
15

PHP가 메모리에 배열을로드하는 방식과 배열을 전달할 때 메모리를 사용하는 방식을 파악하려고합니다.PHP의 배열 메모리 사용량 관리는 어떻게 작동합니까?

그래서 코드 실행이 조금있어 : 입력 배열이 예에서 덜 중요 참고 :

<?php 

echo $this->getMemoryUsage(); 
$arr = $query->result_array(); // array of arrays from codeigniter 
echo $this->getMemoryUsage(); 

이 메모리가 정확히 250 kB의 소비,이 배열은 대략 250 의미 kB 크기, 대략.

그래서 나는 다음과 같은 코드를 실행 :이 변경되면 내가 무엇을 읽고에 따르면

<?php 

echo $this->getMemoryUsage(); 
$arr = $query->result_array(); // array of arrays from codeigniter 

$arr[0]['id'] = 'changing this value'; 

$foo = $arr; 
$foo[2]['id'] = 'changing this value again'; 

$bar = $foo; 
$bar[4]['id'] = 'changing this value again and again'; 

$far = $bar; 
$far[5]['id'] = 'changing this value again and again and again'; 

echo $this->getMemoryUsage(); 

및 들었다, PHP 실제로 배열을 복사하지 않습니다, 그것은 단지 원래의 배열, 하지만를 참조 만든 PHP는 전체 배열을 복사해야합니다.

위의 코드가 정확히 500kB의 RAM을 소비 할 때 놀랍습니다.

여기에 무슨 일이 일어 났는지 설명 할 수 있습니까?

이러한 모든 인덱스 (0-5 및 id)는 원래 배열에 이미 있으므로 값을 수정하고 있습니다. 원래 값은 정수입니다.

편집하는 것은

그냥()> 결과를 ​​$ this-의 참여를 취소합니다; 여기에 내가 수행 한 다른 테스트입니다 :

echo $this->getMemoryUsage(); 
    $arr = $query->result_array(); // array of arrays from codeigniter 
//$arr[0]['id'] = 'changing this value'; 

    $foo = $arr; 
    $foo[2]['id'] = 'changing this value again'; 

    //$bar = $foo; 
    //$bar[4]['id'] = 'changing this value again and again'; 
    // 
    //$far = $bar; 
    //$far[4]['id'] = 'changing this value again and again and again'; 

    echo $this->getMemoryUsage(); 

출력이 정확히 250 KB입니다이 시간 - 그냥

요청으로

편집 # 2

, 나는 '변경하지 않고 원래의 재판처럼 수 있도록, 내 설정에 여기에서 코드를 실행했습니다 확인 결과 일치 : http://pastebin.com/cYNg4cg7

이러한 결과는 다음과 같습니다

선언 : 4608 kB의
FINAL : 8904 kB의 선언에
DIFF : 4296 kB의

선언은 4608이고 배열은 여전히 ​​메모리를 두 배 이상 만 이하의 통과와 4 번 바뀌었다 그래서 비록 발자국.

는 I 메모리 각 할당 후 변경 실행 한 3

EDIT 번호 :

선언 : A0를 할당 5144 kB의
첨가 : A1 할당 144 킬로바이트
첨가 : 1,768 킬로바이트
A2 할당 : 1768 kB
할당 A3 추가 : 1768 kB
최종 : 10744 kB
신고하기까지의 차이 : 5600 kB

첫 번째 작업 이후의 다음 작업은 모두 정확히 동일하므로 정확히 같은 크기가 복사되고 있음을 나타냅니다. 이것은 오스틴의 대답을 뒷받침하는 것처럼 보입니다. 지금은 더할 수없는 유일한 것은 할당 된 크기입니다. 그러나 그것은 다른 질문입니다.

오스틴이 공을 쥐고있는 것처럼 보입니다. 다른 답변이없는 경우 받아 들일 것입니다. 당신이 말한대로

PHP 배열 쓰기 복사, 그러나 다차원 배열의 각 수준은 개별적으로 쓰기에 복사되어

+0

: https : //로 nikic를 .github.io/2011/12/12/얼마나 대단한 PHP 배열인지 - 힌트 -BIG.html – Fleshgrinder

+0

몇 주 전에이 기사를 읽었습니다. 솔직히 fasci입니다. 그러나, 복사가 정확히 어떻게 작동하는지 설명하지는 않습니다. – Patrick

+2

알아, 그냥 네가 좋아할 거라 생각 했어. 귀하의 질문에 답변 할 수 없으며 귀하의 질문에 답변 할 수있는 링크를 드릴 수 없습니다. 대신 나는 당신의 질문에 별표를 붙여서 답변을 게시하지 않을 경우 현상금을 지불하고 현상금을 지급합니다. 알고 있기를 바랍니다. :) – Fleshgrinder

답변

4

여기에 무슨 일이 일어나고 있는지 나는 생각합니다. PHP는 모든 것뿐만 아니라 다차원 배열의 일부를 재사용하는 것에 매우 영리합니다. (이것은 ZFS 같은 스냅 샷을 지원하는 일부 파일 시스템과 유사하다.)

예 : 우리가이가 아닌 하나의 덩어리로 메모리에 저장됩니다

$x = array('foo' => array(1, 2, 3), 'bar' => array(4, 5, 6)); 

이 배열이 있다고하지만, 여기에 별도의 덩어리로 C, B, A 표시 및 $x :

,536 :

array(1, 2, 3) //A 
array(4, 5, 6) //B 
array('foo' => {pointer to A}, 'bar' => {pointer to B}) //C 
{pointer to C} //$x 

지금 $x의 복사본을 만들 수 있습니다 그것은 상관이 모든 C 또 다른 포인터를 만들 수 있기 때문에

$y = $x; 

이것은 아주 약간의 여분의 메모리를 사용합니다

$y['foo'][0] = 10; 

다음은 발생하지 않습니다 무엇 :

array(1, 2, 3) //A 
array(4, 5, 6) //B 
array('foo' => {pointer to A}, 'bar' => {pointer to B}) //C 
{pointer to C} //$x 
{pointer to C} //$y 

지금 변화 $y가 있습니다 :

array(1, 2, 3) //A 
array(10, 2, 3) //A2 
array(4, 5, 6) //B 
array(4, 5, 6) //B2 
array('foo' => {pointer to A}, 'bar' => {pointer to B}) //C 
array('foo' => {pointer to A2}, 'bar' => {pointer to B2}) //C2 
{pointer to C} //$x 
{pointer to C2} //$y 

알림 BB2은 동일합니다. 대신 세 개의 숫자는 'bar' 배열이 숫자의 수천을 포함하는 것이, 이익이 꽤 작이 간단한 경우

array(1, 2, 3) //A 
array(10, 2, 3) //A2 
array(4, 5, 6) //B 
array('foo' => {pointer to A}, 'bar' => {pointer to B}) //C 
array('foo' => {pointer to A2}, 'bar' => {pointer to B}) //C2 
{pointer to C} //$x 
{pointer to C2} //$y 

하지만 상상 :이 같은 일을 계속 할 필요가 그래서 뭐 실제로 일어나는 것은 이것이다, 두 번 없다 . 엄청난 양의 메모리를 절약하게됩니다.

원본 코드와 관련하여 처음부터 끝까지뿐만 아니라 새 배열을 할당 할 때마다 메모리 사용을 인쇄 해보십시오.메모리 사용량이 각 단계마다 원래 배열의 일부분 만 증가한다는 것을 알 수 있습니다. 배열의 일부만이 복사되는 것이지 모든 것이 복사되지 않기 때문입니다. 특히 변경 한 첫 번째 수준 배열과 특정 하위 배열은 복사되지만 다른 하위 배열은 복사되지 않습니다.

사용 된 메모리의 양이 시작 양의 두 배가된다는 사실은 코드의 특정 설정과 배열의 복사본 수 때문에 발생하는 것으로 보입니다.

(실제로는 PHP가 여기에 설명 된 것보다 훨씬 뛰어날 수 있습니다 ('foo''bar' 등의 사본 한 개만 남기도합니다). 그러나 대부분 같은 종류의 속임수로 끝납니다.)

이의 더 극적인 데모를하려면이 같은 수행

매우 어려운 질문, 당신은 내가 며칠 전에 읽은 다음 문서에 관심이있을 수
$base = memory_get_usage(); 
$x = array('small' => array('this is small'), 'big' => array()); 
for ($i = 0; $i < 1000000; $i++) { 
    $x['big'][] = $i; 
} 
echo (memory_get_usage() - $base).PHP_EOL; //a lot of memory 
$y = $x; 
$y['small'][0] = 'now a bit bigger'; 
echo (memory_get_usage() - $base).PHP_EOL; //a bit more memory 
$z = $x; 
$z['big'][0] = 2; 
echo (memory_get_usage() - $base).PHP_EOL; //a LOT more memory 
+0

어이, 나는이 라인을 따라 뭔가를 생각하고 있었다. 그러나 그것은 합치 지 않았다. 또 다른 테스트 케이스를 사용하여 그것은 4 개의 동일한 액션 후에 메모리 할당이 두 배가되었다는 것을 이미 재현했다. 같은 크기의 배열에서 4 개의 동일한 작업이 선형 효과를 가져야합니다. 정확히 동일한 작업을 네 번 수행하면 한 번만 비용의 4 분의 1을 소비해야합니다. 테스트에서 나는 다른 인덱스를 계속 변경합니다. 하나를 복사하면 모두 복사됩니다. 최대한 빨리 새로운 메모리 값으로 질문을 편집하겠습니다. – Patrick

+2

@Patrick 변수가 없으므로 이전 값을 유지할 필요가 없으므로 첫 번째 작업의 비용이 많이 들지 않습니다. 원본이 아직 사용 중이므로 두 번째에서 네 번째 작업은 복사본을 만들어야합니다.매번 할당 후에 메모리 사용량을 표시하여이를 확인하십시오. – Austin

+0

더 많은 테스트를 거친 후에 실제로 답이 정확합니다. :) – Patrick

관련 문제