PHP变量内存占用分析

来源:互联网 发布:常用数据采集卡型号 编辑:程序博客网 时间:2024/04/30 11:55

前言

都说PHP内存占有率太大,究竟有多大,有个量级吗?一起来看看吧。

1. 环境假设

PHP5.4.3|64位机器

2. 从PHP变量存储结构看存储空间大小

  • 2.1 原生类型(boolean,char,int,short,long,float,double)
    PHP中,所有变量存储为zval

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

    考虑8字节内存对齐,定义8字节向上取整伪函数ceil8()。sizeof(zval)=ceil8(sizeof(zvalue_value+4+1+1))。
    再看zvalue_value

    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;

    sizeof(zvalue_value)=max(sizeof(str),sizeof(zend_object_value))=max(16,sizeof(zend_object_value))。
    再看zend_object_value

    typedef unsigned int zend_object_handle;typedef struct _zend_object_handlers zend_object_handlers;typedef struct _zend_object_value {    zend_object_handle handle;    const zend_object_handlers *handlers;} zend_object_value;

    sizeof(zend_object_value)=16
    合计一下,原生类型(boolean,char,int,long,float,double)在PHP中的存储大小=sizeof(zval)=24。

  • 2.2 空类大小
    回到2.1节中关于sizeof(zvalue_value)的讨论。对于空类而言,zvalue_value的内存大小由两部分组成,一部分是sizeof(zvalue_value),另一部分是sizeof(zend_object_handlers)。而zend_object_handlers定义为

    struct _zend_object_handlers {    /* general object functions */    zend_object_add_ref_t                   add_ref;    zend_object_del_ref_t                   del_ref;    zend_object_clone_obj_t                 clone_obj;    /* individual object functions */    zend_object_read_property_t             read_property;    zend_object_write_property_t            write_property;    zend_object_read_dimension_t            read_dimension;    zend_object_write_dimension_t           write_dimension;    zend_object_get_property_ptr_ptr_t      get_property_ptr_ptr;    zend_object_get_t                       get;    zend_object_set_t                       set;    zend_object_has_property_t              has_property;    zend_object_unset_property_t            unset_property;    zend_object_has_dimension_t             has_dimension;    zend_object_unset_dimension_t           unset_dimension;    zend_object_get_properties_t            get_properties;    zend_object_get_method_t                get_method;    zend_object_call_method_t               call_method;    zend_object_get_constructor_t           get_constructor;    zend_object_get_class_entry_t           get_class_entry;    zend_object_get_class_name_t            get_class_name;    zend_object_compare_t                   compare_objects;    zend_object_cast_t                      cast_object;    zend_object_count_elements_t            count_elements;    zend_object_get_debug_info_t            get_debug_info;    zend_object_get_closure_t               get_closure;    zend_object_get_gc_t                    get_gc;};

    所有的zend_**_t都是函数指针,sizeof(zend_object_handlers)=26*8=208。
    因此,一个空类占用的内存空间为sizeof(zval)+sizeof(zvalue_value)+sizeof(zend_object_handlers)=248。

  • 2.3 数组
    PHP中数组以HashTable实现。

    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;typedef void (*dtor_func_t)(void *pDest);typedef unsigned char zend_bool;

    考虑n维数组。HashTable的内存大小由两部分组成:sizeof(HashTable)以及n*sizeof(Bucket)。
    考虑n维数组并忽略ZEND_DEBUG,sizeof(HashTable)=4+4+4+8+8+8+8+8+8+1+1+1=64。
    来看下Bucket

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

    Bucket的内存大小由两部分组成,sizeof(Bucket)以及pData指向的数据,通常是zval或者zval*,因此可以用sizeof(zval)去量化。
    sizeof(Bucket)=ceil8(8+4+8*7)=72。
    合计一下,对于2.1节的原生数组,一个n维数组的大小为sizeof(HashTable)+n*(sizeof(Bucket)+sizeof(zval))=64+96n。
    对于2.2节的空类数组,一个n维数组的大小为sizeof(HashTable)+n*(sizeof(Bucket)+sizeof(zval))=64+320n。

3. 高级语言间横向对比

好了,这回和邻居家的语言JAVA,C++比较下,看看差距。这里假设C++编译环境为64位机器,JAVA的虚拟机环境为64位,hotspot

语言PHPJAVAC++boolen/bool2411short2422int2444long2488float2444double2488char2421空类248241原生类型数组[n]64+96nn*sizeof(原生类型)n*sizeof(原生类型)空对象数组[n]64+320n24nn
0 0
原创粉丝点击