PHP 자작 TypedArray (어둠)

8654 단어 PHParray배열
PHP 자작 TypedArray 의 암판입니다.
PHP의 배열이 많은 메모리를 사용하는 것은 왜? 라는 이야기. (타이틀 실패.)

어둠이라고 해도 다크 사이드가 아니라, 뒤쪽인 PHP 내부 실장(C언어)의 이야기입니다. 그리고, 어디까지나 PHP5의 이야기입니다. PHP7은 다르다.

소개



PHP 의 array 는 단순히 번호를 지정해 값을 격납할 수 있을 뿐만 아니라. 문자열을 키에 격납해 연상 배열로서 사용하거나, 격납한 차례로 꺼낼 수 있다고, 과해라고 해도 좋을 만큼 고성능인 대물입니다.

C언어에서는 선언한 형태의 값을 번호 지정으로 격납할 수 밖에 할 수 없기 때문에, 그것들을 실현하기 위해서 상당히 노력하고 있습니다.
참고를 위해서, array 의 관리 데이터인 HashTable 의 구조체를 인용합니다.

HashTable



c
typedef struct bucket {
        ulong h;                                                /* Used for nume
ric indexing */
        uint nKeyLength;
        void *pData;
        void *pDataPtr;
        struct bucket *pListNext;
        struct bucket *pListLast;
        struct bucket *pNext;
        struct bucket *pLast;
        const char *arKey;
} Bucket;

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

그림으로 하면 다음과 같은 느낌입니다.


인용 소스) h tps://d ゔぇ. 오, ぇ. 코 m/후우/d/0B3 마코 MH_4lg부 Td주GぃZ3l1우 k/ゔぃ에w

느긋하게 간략화한 알기 쉬운 그림도 발견했습니다.


인용 소스) htps : // 또는 tchy. 이오/sぃ에서 s/PHP-다타-St るcつれ s-안 d-테-이 m파 ct-오-PHP-7-온-테 m. HTML

왠지 여러가지 얽혀 있습니다. 메모리를 많이 사용하는 것은 왠지 이미지 할 수 있다고 생각합니다.
그리고 PHP5.3에서 도입된 SplFixedArray는 길이를 고정 길이로 하고 중간 구조를 가볍게 생략하여 메모리 사용량이 절반 정도까지 줄입니다.

그렇지만 어쩌면 그래도 절반입니다. PHP의 표준 array도 SplFixedArray도 요소로서 어떤 형태라도 들어가는 변수 컨테이너로서 보존하기 때문입니다.

Zval 구조체



PHP의 변수 컨테이너는 여러분에게 친숙한 Zval 구조체로 표현됩니다.

php-5.5.28/Zend/zend.h
typedef union _zvalue_value {
        long lval;                                      /* long value */
        double dval;                            /* double value */
        struct {
                char *val;
                int len;
        } str;
        HashTable *ht;                          /* hash table value */
        zend_object_value obj;
} zvalue_value;

struct _zval_struct {
        /* Variable information */
        zvalue_value value;             /* value */
        zend_uint refcount__gc;
        zend_uchar type;        /* active type */
        zend_uchar is_ref__gc;
};

zvalue_value 의 C언어 union(공용체) 는 내부에서 선언한 어느 형태라도 사용할 수 있도록(듯이), 그 중에서 가장 큰 형태에 맞추어 메모리를 확보합니다. 게다가 zval_struct 의 관리 데이터량도 바보가 되지 않습니다.


인용 소스) h tp // w w. s에서 멋지다. 네 t/hw/야미 php-20140315/13

즉, 배열 요소에 어떤 작은 (레인지의) 값을 보존해도, 변수 하나당 24byte(Zval 구조체) + 8byte(리스트로부터의 포인터)로 34byte가 필요하다고 하는 것입니다.

string (문자열 유형)



반면에 PHP 문자열은 zvalue_value의 struct str 뿐이며 char *와 len이라는 단단한 구조입니다.

php-5.5.28/Zend/zend.h
typedef union _zvalue_value {
<略>
        struct {
                char *val;
                int len;
        } str;

} zvalue_value;

저장하고 싶은 값이 byte 단위이면, 복수의 byte 를 pack 하고 이 string 로서 보존하면, 1byte 의 데이터는 1byte 분 밖에 소비하지 않습니다.

array 를 사용하지 않고 string 로서 격납해 메모리 절약이라고 하는 것은 이전부터 하고 있었습니다만, 배열풍에 액세스 할 수 있는 class 를 만들어 보았다. 라는 것이 「PHP 자작 TypedArray」의 재료였습니다.

P.S. 이것의 PHP 확장을 만들어 엔트리로 할 생각이었습니다만, 별로 수요가 없기 때문에(지금까지 코멘트 받은 것이 2명), 그 중 여가가 되면 합니다. 아니면 누군가 해주세요. :-)

좋은 웹페이지 즐겨찾기