zoukankan      html  css  js  c++  java
  • php7 改为从栈上分配内在的思路

    php7的特点是规则上不从堆上分配内存,改为从栈上分配内存,

    因为有些场景是从堆上分配内在后,还要手动释放内存,利用栈分配内在快的特点,在有需要的时候,再在堆上分配内在

    但是栈上分配的内存,不能返回,因为当函数运行完后,就退栈了,但可以将该内在地址传给别的函数

    php7的hashTable中的Bucket中的zval不再是指针,而是直接存储zval

    由于从php代码上不好分析,只要从扩展上分析

    <?php
    $a=array();
    $a['name']='taek-007';
    ?>
    
    ///////////////////////////////////////////////////////////////////////
    
    PHP_FUNCTION(confirm_variable_compiled)
    {
        zval val;
        array_init(&val);
        add_assoc_string(&val, "name", "taek-007");
    
        RETURN_ZVAL(&val,1,0);
    }

    为了能在gdb调试中打开宏,在编译php之前,修改configure该文件,增加红色的字样

     15533 if test "$PHP_DEBUG" = "yes"; then
      15534   PHP_DEBUG=1
      15535   ZEND_DEBUG=yes
      15536 
      15537   CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9s]*//g'`
      15538   CXXFLAGS=`echo "$CXXFLAGS" | $SED -e 's/-O[0-9s]*//g'`
      15539 
      15540     if test "$GCC" = "yes" || test "$ICC" = "yes"; then
      15541     CFLAGS="$CFLAGS -gdwarf-2 -g3  -O0"

    直接上gdb调试吧

    gdb /usr/local/php/bin/php

    (gdb)
    (gdb) source /home/source/php-7.0.2/.gdbinit

    (gdb) break /home/source/php-7.0.2/ext/variable/variable.c:66
    No source file named /home/source/php-7.0.2/ext/variable/variable.c.
    Make breakpoint pending on future shared library load? (y or [n]) y

    Breakpoint 1 (/home/source/php-7.0.2/ext/variable/variable.c:66) pending.
    (gdb)

    (gdb) run /home/debug_php/variable.php
    Starting program: /usr/local/php/bin/php /home/debug_php/variable.php
    [Thread debugging using libthread_db enabled]
    [New Thread 0xb7f4e6c0 (LWP 3761)]

    Breakpoint 1, zif_confirm_variable_compiled (execute_data=0xb7c15090,
    return_value=0xb7c15060) at /home/source/php-7.0.2/ext/variable/variable.c:67
    67 array_init(&val);

    (gdb) n
    68 add_assoc_string(&val, "name", "taek-007");
    (gdb) s
    add_assoc_string_ex (arg=0xbf80cddc, key=0x493a7c "name", key_len=4,
    str=0x493a73 "taek-007") at /home/source/php-7.0.2/Zend/zend_API.c:1383
    1383 ZVAL_STRING(&tmp, str);
    (gdb) macro expand ZVAL_STRING(&tmp, str)
    expands to: do { const char *_s = (str); do { do { zval *__z = (&tmp); zend_string *__s = (zend_string_init(_s, strlen(_s), 0)); (*(__z)).value.str = __s; (*(__z)).u1.type_info = (6 | (( (1<<2) | (1<<4)) << 8)); } while (0); } while (0); } while (0)

    (gdb) p (char*)str
    $4 = 0x493a73 "taek-007"

    (gdb) s
    zend_string_init (str=0xe22a73 "taek-007", len=8, persistent=0)
    at /home/source/php-7.0.2/Zend/zend_string.h:157
    157 zend_string *ret = zend_string_alloc(len, persistent);

    (gdb) n
    159 memcpy(ZSTR_VAL(ret), str, len);

    (gdb) p ret
    $39 = (zend_string *) 0xb7c58900  //可以发现从堆上分配内存给了ret

    (gdb) n
    160 ZSTR_VAL(ret)[len] = '';

    (gdb) p (char *)ret.val
    $47 = 0xb7c58910 "taek-007"

    .... 一直n

    1384 ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
    (gdb) p tmp.value.str
    $51 = (zend_string *) 0xb7c58900  

    (gdb) p tmp.value
    $54 = {lval = -1211791104, dval = 1.8828939190657202e-307, counted = 0xb7c58900,
    str = 0xb7c58900, arr = 0xb7c58900, obj = 0xb7c58900, res = 0xb7c58900,
    ref = 0xb7c58900, ast = 0xb7c58900, zv = 0xb7c58900, ptr = 0xb7c58900,
    ce = 0xb7c58900, func = 0xb7c58900, ww = {w1 = 3083176192, w2 = 4254880}} //由于value本身是个结构体,故其中每个元素的地址都是0xb7c58900

    (gdb) s  //进入函数zend_symtable_str_update
    zend_symtable_str_update (ht=0xb7c59300, str=0xe22a7c "name", len=4,
    pData=0xbfd1d0c4) at /home/source/php-7.0.2/Zend/zend_hash.h:392
    392 if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) {
    (gdb)

    (gdb) n
    395 return zend_hash_str_update(ht, str, len, pData);
    (gdb) s
    _zend_hash_str_update (ht=0xb7c59300, str=0xe22a7c "name", len=4, pData=0xbfd1d0c4,
    __zend_filename=0x895c438 "/home/source/php-7.0.2/Zend/zend_hash.h",
    __zend_lineno=395) at /home/source/php-7.0.2/Zend/zend_hash.c:653
    653 zend_string *key = zend_string_init(str, len, ht->u.flags & HASH_FLAG_PERSISTENT);

    (gdb) n
    654 zval *ret = _zend_hash_add_or_update_i(ht, key, pData, HASH_UPDATE ZEND_FILE_LINE_RELAY_CC);

    (gdb) p (char*)key.val
    $56 = 0xb7c58940 "name"

    (gdb) p (char *)pData.value.str.val
    $58 = 0xb7c58910 "taek-007"

    (gdb) p pData.value.str
    $60 = (zend_string *) 0xb7c58900

    (gdb) s
    _zend_hash_add_or_update_i (ht=0xb7c59300, key=0xb7c58930, pData=0xbfd1d0c4, flag=1,
    __zend_filename=0x895c438 "/home/source/php-7.0.2/Zend/zend_hash.h",
    __zend_lineno=395) at /home/source/php-7.0.2/Zend/zend_hash.c:559
    559 IS_CONSISTENT(ht);
    (gdb) n
    562 if (UNEXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
    (gdb)
    563 CHECK_INIT(ht, 0); //检查hashtable情况
    (gdb) macro expand CHECK_INIT(ht, 0)
    expands to: zend_hash_check_init(ht, 0)
    (gdb) s
    zend_hash_check_init (ht=0xb7c59300, packed=0)
    at /home/source/php-7.0.2/Zend/zend_hash.c:162
    162 if (UNEXPECTED(!((ht)->u.flags & HASH_FLAG_INITIALIZED))) {
    (gdb) n
    163 zend_hash_real_init_ex(ht, packed);

    (gdb) s
    zend_hash_check_init (ht=0xb7c59300, packed=0)
    at /home/source/php-7.0.2/Zend/zend_hash.c:162
    162 if (UNEXPECTED(!((ht)->u.flags & HASH_FLAG_INITIALIZED))) {
    (gdb) n
    163 zend_hash_real_init_ex(ht, packed);
    (gdb) s
    zend_hash_real_init_ex (ht=0xb7c59300, packed=0)
    at /home/source/php-7.0.2/Zend/zend_hash.c:133
    133 ZEND_ASSERT(!((ht)->u.flags & HASH_FLAG_INITIALIZED));
    (gdb) n
    134 if (packed) {
    (gdb)
    139 (ht)->nTableMask = -(ht)->nTableSize;
    (gdb)
    140 HT_SET_DATA_ADDR(ht, pemalloc(HT_SIZE(ht), (ht)->u.flags & HASH_FLAG_PERSISTENT));

    (gdb) p packed
    $61 = 0
    (gdb) p ht->nTableSize
    $62 = 8

    (gdb) macro expand HT_SET_DATA_ADDR  //分配8个Bucket大小的内存,并将首地址赋给ht->arData
    expands to: HT_SET_DATA_ADDR
    (gdb) macro expand HT_SET_DATA_ADDR(ht, pemalloc(HT_SIZE(ht), (ht)->u.flags & HASH_FLAG_PERSISTENT));
    expands to: do { (ht)->arData = (Bucket*)(((char*)((((ht)->u.flags & (1<<0))?__zend_malloc((((size_t)(((ht)->nTableSize)) * sizeof(Bucket)) + (((size_t)(uint32_t)-(int32_t)(((ht)->nTableMask))) * sizeof(uint32_t)))):_emalloc(((((size_t)(((ht)->nTableSize)) * sizeof(Bucket)) + (((size_t)(uint32_t)-(int32_t)(((ht)->nTableMask))) * sizeof(uint32_t)))) , __FILE__, __LINE__ , ((void *)0), 0)))) + (((size_t)(uint32_t)-(int32_t)((ht)->nTableMask)) * sizeof(uint32_t))); } while (0);

    (gdb) n
    141 (ht)->u.flags |= HASH_FLAG_INITIALIZED;
    (gdb)
    142 if (EXPECTED(ht->nTableMask == -8)) {
    (gdb)
    143 Bucket *arData = ht->arData;
    (gdb)
    145 HT_HASH_EX(arData, -8) = -1;
    (gdb)
    146 HT_HASH_EX(arData, -7) = -1;
    (gdb)
    147 HT_HASH_EX(arData, -6) = -1;
    (gdb)
    148 HT_HASH_EX(arData, -5) = -1;
    (gdb)
    149 HT_HASH_EX(arData, -4) = -1;
    (gdb)
    150 HT_HASH_EX(arData, -3) = -1;
    (gdb)
    151 HT_HASH_EX(arData, -2) = -1;
    (gdb)
    152 HT_HASH_EX(arData, -1) = -1;
    (gdb)
    157 }
    (gdb)
    zend_hash_check_init (ht=0xb7c59300, packed=0)
    at /home/source/php-7.0.2/Zend/zend_hash.c:165
    165 }
    (gdb)
    _zend_hash_add_or_update_i (ht=0xb7c59300, key=0xb7c58930, pData=0xbfd1d0c4, flag=1,
    __zend_filename=0x895c438 "/home/source/php-7.0.2/Zend/zend_hash.h",
    __zend_lineno=395) at /home/source/php-7.0.2/Zend/zend_hash.c:564
    564 goto add_to_hash;
    (gdb)
    595 idx = ht->nNumUsed++;

    (gdb) n
    596 ht->nNumOfElements++;
    (gdb) p ht->nNumUsed++
    $64 = 2
    (gdb) p idx
    $65 = 1
    (gdb) n
    597 if (ht->nInternalPointer == HT_INVALID_IDX) {
    (gdb)
    598 ht->nInternalPointer = idx;
    (gdb)
    600 zend_hash_iterators_update(ht, HT_INVALID_IDX, idx);
    (gdb)
    601 p = ht->arData + idx;

    $67 = (Bucket *) 0xb7c60620
    (gdb) p ht->arData+1
    $68 = (Bucket *) 0xb7c60638
    (gdb) n
    602 p->key = key;
    (gdb) p p
    $69 = (Bucket *) 0xb7c60638

    (gdb) p idx
    $70 = 1
    (gdb) n
    603 if (!ZSTR_IS_INTERNED(key)) {
    (gdb)
    604 zend_string_addref(key);
    (gdb)
    605 ht->u.flags &= ~HASH_FLAG_STATIC_KEYS;
    (gdb)
    606 zend_string_hash_val(key);
    (gdb)
    608 p->h = h = ZSTR_H(key);
    (gdb)
    609 ZVAL_COPY_VALUE(&p->val, pData); //(*(_z1)).value.counted = _gc; 将堆上的内存地址分配到了hashTable中的Bucket中的val中的value.str
    (gdb) macro expand ZVAL_COPY_VALUE(&p->val, pData)
    expands to: do { zval *_z1 = (&p->val); const zval *_z2 = (pData); zend_refcounted *_gc = (*(_z2)).value.counted; uint32_t _t = (*(_z2)).u1.type_info; do { uint32_t _w2 = _z2->value.ww.w2; (*(_z1)).value.counted = _gc; _z1->value.ww.w2 = _w2; (*(_z1)).u1.type_info = _t; } while (0); } while (0)
    (gdb) p p->val
    $71 = {value = {lval = 0, dval = 0, counted = 0x0, str = 0x0, arr = 0x0, obj = 0x0,
    res = 0x0, ref = 0x0, ast = 0x0, zv = 0x0, ptr = 0x0, ce = 0x0, func = 0x0,
    ww = {w1 = 0, w2 = 0}}, u1 = {v = {type = 0 '', type_flags = 0 '',
    const_flags = 0 '', reserved = 0 ''}, type_info = 0}, u2 = {var_flags = 0,
    next = 0, cache_slot = 0, lineno = 0, num_args = 0, fe_pos = 0, fe_iter_idx = 0}}
    (gdb) p pData.value
    $72 = {lval = -1211791104, dval = 1.8828939190657202e-307, counted = 0xb7c58900,
    str = 0xb7c58900, arr = 0xb7c58900, obj = 0xb7c58900, res = 0xb7c58900,
    ref = 0xb7c58900, ast = 0xb7c58900, zv = 0xb7c58900, ptr = 0xb7c58900,
    ce = 0xb7c58900, func = 0xb7c58900, ww = {w1 = 3083176192, w2 = 4254880}}
    (gdb) p pData.value.counted
    $73 = (zend_refcounted *) 0xb7c58900
    (gdb) p (*(_z1)).value.counted
    Cannot access memory at address 0x30
    (gdb) p p->val.value.counted
    $74 = (zend_refcounted *) 0x0
    (gdb) p pData.u.type_info
    There is no member named u.
    (gdb) p pData.u1.type_info
    $75 = 5126
    (gdb) p p->val.value.u1.type_info
    There is no member named u1.
    (gdb) p p->val.u1.type_info
    $76 = 0
    (gdb) n
    610 nIndex = h | ht->nTableMask;
    (gdb) p p->val.value.counted
    $77 = (zend_refcounted *) 0xb7c58900
    (gdb) p p->val.value.u1.type_info
    There is no member named u1.
    (gdb) p p->val.u1.type_info
    $78 = 5126
    (gdb)

    (gdb) n
    610 nIndex = h | ht->nTableMask;
    (gdb) p p->val.value.counted
    $77 = (zend_refcounted *) 0xb7c58900
    (gdb) p p->val.value.u1.type_info
    There is no member named u1.
    (gdb) p p->val.u1.type_info
    $78 = 5126
    (gdb) n
    611 Z_NEXT(p->val) = HT_HASH(ht, nIndex);
    (gdb) p HT_HASH(ht, nIndex);
    Invalid character ';' in expression.
    (gdb) n
    612 HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
    (gdb) p HT_HASH(ht, nIndex)
    $79 = 4294967295
    (gdb) n
    615 return &p->val;
    (gdb) p HT_HASH(ht, nIndex)
    $80 = 24
    (gdb) p HT_IDX_TO_HASH(idx)
    $81 = 24
    (gdb) p idx
    $82 = 1
    (gdb) p HT_HASH(ht, nIndex)
    $83 = 24
    (gdb) macro expand HT_HASH(ht, nIndex)
    expands to: ((uint32_t*)((ht)->arData))[(int32_t)(nIndex)]
    (gdb) macro expand HT_IDX_TO_HASH(idx)
    expands to: ((idx) * sizeof(Bucket))
    (gdb) p sizeof(Bucket)
    $84 = 24
    (gdb) p nIndex
    $85 = 4294967294
    (gdb) p h
    $86 = 4238019654
    (gdb) p ht->nTableMask
    $87 = 4294967288
    (gdb) l
    610 nIndex = h | ht->nTableMask;
    611 Z_NEXT(p->val) = HT_HASH(ht, nIndex);
    612 HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
    613 HANDLE_UNBLOCK_INTERRUPTIONS();
    614
    615 return &p->val;
    616 }

  • 相关阅读:
    大型网站的可伸缩性架构如何设计?
    前端路由跳转基本原理
    强大的CSS:用纯css模拟下雪的效果
    package.json 和 package-lock.json 文件说明
    CSS 继承深度解析
    EJS-初识
    百度前端学院-基础学院-第20到21天之setTimeOut与setInterval
    百度前端学院-基础学院-第20到21天
    es6字符串方法
    字符串方法之padStart和padEnd
  • 原文地址:https://www.cnblogs.com/taek/p/5537172.html
Copyright © 2011-2022 走看看