>  기사  >  백엔드 개발  >  PHP 배열 메모리 사용량 분석

PHP 배열 메모리 사용량 분석

藏色散人
藏色散人앞으로
2019-12-09 17:54:092309검색

다음 방법은 얼마나 많은 메모리를 차지합니까?

list($appid,$openid) = ["testcontent","test"];

Test

$m0 = memory_get_usage();
$k = range(1,200000);
$m1 = memory_get_usage();
echo round(($m1-$m0)/pow(1024,2),4) ."MB\n";
foreach ($k as $i){
    $n1 = "kk$i";
    $n2 = "tt$i";
    list($$n1,$$n2) = [$i,$i*3];
}
$m2 = memory_get_usage();
echo round(($m2-$m1)/pow(1024,2),4) ."MB\n";
$m1 = memory_get_usage();
foreach ($k as $i){
    $n1 = "kk$i";
    $n2 = "tt$i";
    $$n1 = $i+time();
    $$n2 = 2*time();
}
$m2 = memory_get_usage();
echo round(($m2-$m1)/pow(1024,2),4) ."MB\n";

위 연산의 출력 결과는 다음과 같습니다.

27.9404MB
51.3041MB
9.1553MB

어레이가 차지하는 메모리가 일반적으로 할당된 콘텐츠보다 훨씬 크다는 것을 알 수 있습니다

Principle

In PHP는 숫자를 표현하기 위해 long 타입을 사용하고 int 타입은 없습니다. PHP는 변수 유형을 구별하지 않으며 int float char *와 같은 개념이 없습니다. PHP가 zend에 저장하는 변수를 살펴보겠습니다. PHP의 각 변수에는 해당 zval이 있습니다. Zval 구조는 Zend/zend.h에 정의되어 있습니다.

typedef struct _zval_struct zval;  
struct _zval_struct {  
    /* Variable information */  
    zvalue_value value;     /* The value 1 12字节(32位机是12,64位机需要8+4+4=16) */  
    zend_uint refcount__gc; /* The number of references to this value (for GC) 4字节 */  
    zend_uchar type;        /* The active type 1字节*/  
    zend_uchar is_ref__gc;  /* Whether this value is a reference (&) 1字节*/  
};

PHP는 변수를 저장하기 위해 UNION 구조를 사용합니다. 즉, zvalue_value는 공용체이며 UNION 변수가 차지하는 메모리는 최대 멤버 데이터 공간에 따라 결정됩니다.

typedef union _zvalue_value {  
    long lval;                  /* long value */  
    double dval;                /* double value */  
    struct {                    /* string value */  
        char *val;  
        int len;  
    } str;   
    HashTable *ht;              /* hash table value */  
    zend_object_value obj;      /*object value */  
} zvalue_value;

가장 큰 멤버 데이터 공간은 struct str이고, 포인터는 *val에 대해 4바이트를 차지하고, INT는 4바이트를 차지하여 총 8바이트입니다.

struct zval은 8+4+1+1 = 14바이트를 차지합니다. 실제로 zval의 배열, 문자열 및 개체에는 Zend/zend_hash.h에 정의된 HashTable:

HashTable 구조가 필요합니다.

typedef struct _hashtable {  
    uint nTableSize;//4  
    uint nTableMask;//4  
    uint nNumOfElements;//4  
    ulong nNextFreeElement;//4  
    Bucket *pInternalPointer;   /* Used for element traversal 4*/  
    Bucket *pListHead;//4  
    Bucket *pListTail;//4  
    Bucket **arBuckets;//4  
    dtor_func_t pDestructor;//4  
    zend_bool persistent;//1  
    unsigned char nApplyCount;//1  
    zend_bool bApplyProtection;//1  
#if ZEND_DEBUG  
    int inconsistent;//4  
#endif  
} HashTable;

HashTable 구조에는 39바이트가 필요하며 각 배열 요소는 Bucket 구조에 저장됩니다.

typedef struct bucket {  
    ulong h;    /* Used for numeric indexing                4字节 */  
    uint nKeyLength;    /* The length of the key (for string keys)  4字节 */  
    void *pData;        /* 4字节*/  
    void *pDataPtr;         /* 4字节*/  
    struct bucket *pListNext;  /* PHP arrays are ordered. This gives the next element in that order4字节*/  
    struct bucket *pListLast;  /* and this gives the previous element           4字节 */  
    struct bucket *pNext;      /* The next element in this (doubly) linked list     4字节*/  
    struct bucket *pLast;      /* The previous element in this (doubly) linked list     4字节*/  
    char arKey[1];            /* Must be last element   1字节*/  
} Bucket;

Bucket 구조에는 33바이트가 필요하며 키 길이가 4바이트보다 긴 부분은 Bucket 뒤에 요소 값이 추가됩니다. 또한 각 배열에는 arBuckets가 가리키는 버킷 포인터 배열이 할당됩니다. 추가된 각 요소마다 포인터가 필요하다고 말할 수는 없지만 실제 상황은 더 나쁠 수 있습니다. 이는 하나의 배열 요소가 54바이트를 차지할 것으로 계산되며 이는 위의 추정과 거의 동일합니다.

빈 배열은 최소 14(zval) + 39(HashTable) + 33(arBuckets) = 86바이트를 차지합니다. 변수로서 기호 테이블에 위치가 있어야 하며 배열 요소이기도 하므로 비어 있습니다. 설명하고 저장하려면 배열 변수 118바이트가 필요합니다. 공간적인 관점에서 볼 때 작은 배열은 평균적으로 더 비쌉니다. 물론 스크립트는 많은 수의 작은 배열로 채워지지 않으며 더 작은 공간 비용으로 프로그래밍 편의성을 얻을 수 있습니다. 그러나 배열을 컨테이너로 사용하면 이야기가 달라집니다. 실제 응용 프로그램에서는 요소가 많은 다차원 배열을 자주 접하게 됩니다. 예를 들어, 10k 요소의 1차원 배열은 약 540k의 메모리를 소비하는 반면 10k의 2차원 배열은 실제로 23M을 소비하므로 작은 배열은 실제로 그만한 가치가 없습니다.

위 내용은 PHP 배열 메모리 사용량 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제