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,,);
}

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

  if test "$PHP_DEBUG" = "yes"; then
PHP_DEBUG=
ZEND_DEBUG=yes CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9s]*//g'`
CXXFLAGS=`echo "$CXXFLAGS" | $SED -e 's/-O[0-9s]*//g'` if test "$GCC" = "yes" || test "$ICC" = "yes"; then
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] = '\0';

(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 '\0', type_flags = 0 '\0',
const_flags = 0 '\0', reserved = 0 '\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 }

php7 改为从栈上分配内在的思路的更多相关文章

  1. 如何限制一个类只在堆上分配和栈上分配(StackOnly HeapOnly)

    [本文链接] http://www.cnblogs.com/hellogiser/p/stackonly-heaponly.html [题目] 如何限制一个类只在堆上分配和栈上分配? [代码]  C+ ...

  2. Java中的栈上分配

    博客搬家自https://my.oschina.net/itsyizu/blog/ 什么是栈上分配 栈上分配是java虚拟机提供的一种优化技术,基本思想是对于那些线程私有的对象(指的是不可能被其他线程 ...

  3. JVM之对象分配:栈上分配 & TLAB分配

    1. Java对象分配流程 2. 栈上分配 2.1 本质:Java虚拟机提供的一项优化技术 2.2 基本思想: 将线程私有的对象打散分配在栈上 2.3 优点: 2.3.1 可以在函数调用结束后自行销毁 ...

  4. 【深入浅出-JVM】(7):栈上分配

    概念 对那些作用于不会逃逸出方法的对象,在分配内存时,不在将对象分配在堆内存中,而是将对象属性打散后分配在线程私有栈内存上,这样随着方法调用结束,栈上分配打散的对象也被回收掉,不在增加 GC 额外压力 ...

  5. 【LWJGL3】LWJGL3的内存分配设计,第一篇,栈上分配

    简介 LWJGL (Lightweight Java Game Library 3),是一个支持OpenGL,OpenAl,Opengl ES,Vulkan等的Java绑定库.<我的世界> ...

  6. LWJGL3的内存管理,第二篇,栈上分配

    LWJGL3的内存管理,第二篇,栈上分配 简介 为了讨论LWJGL在内存分配方面的设计,本文将作为该系列随笔中的第二篇,用来讨论在栈上进行内存分配的策略,该策略在 LWJGL3 中体现为以 Memor ...

  7. 【小实验】rust的数组是在堆上分配还是在栈上分配的呢?

    先看代码: fn main(){ let v = [1,2,3,4,5]; let addr = &v[0] as *const i32 as usize; println!("ar ...

  8. Java对象栈上分配

    转自 https://blog.csdn.net/o9109003234/article/details/101365108 在学习Java的过程中,很多喜欢说new出来的对象分配一定在对上: 其实不 ...

  9. 栈上分配存储器的方法 alloca 抽样

    声明一个局部变量,必须分配在堆栈上,但有或没有它的方法 当然,,那是 alloca 下面的代码显示了可变长度参数转换,alloca 要使用 int main(int argc, char ** arg ...

随机推荐

  1. 专2-第二课 Eclipse开发环境搭建

    2.1下载Eclipse 2.2 安装C/C++版本的Eclipse 2.3 安装JDT插件开发Java程序 2.4 使用Eclipse开发驱动程序 既然安装了eclipse来进行驱动学习,那么我们就 ...

  2. 解决JS中missing ( before function parameters的错误

    在编写javascript中,常出现在function处提示“missing ( before function parameters”的错误,这是怎么回事? 例如: function String. ...

  3. 高性能 js -- 无阻塞加载脚本

    参考: <<高性能JavaScript>> Nicbolas C. Zakas 著 javascript代码的下载和执行过程会阻塞浏览器的其他进程, 比如页面的绘制, 遇到&l ...

  4. python之零碎知识

    一 join方法 主要是做字符串的拼接:join后面跟的类型必须是要可迭代得到对象 for循环的对象是可迭代对象 # result = "".join(li) # print(re ...

  5. 2018.07.27 bzoj3064: Tyvj 1518 CPU监控(线段树)

    传送门 线段树好题. 维护区间加,区间覆盖,区间最大,区间历史最大. 这个东西在国家集训队2016论文集之<区间最值操作与历史最值问题--杭州学军中学 吉如一>中讲的已经很详细了. 简单来 ...

  6. 2018.07.06 POJ2536 Gopher II(二分图匹配)

    Gopher II Time Limit: 2000MS Memory Limit: 65536K Description The gopher family, having averted the ...

  7. hdu-1179(匈牙利算法)

    题目链接: 思路:找n个巫师和m个魔棒匹配的问题,匈牙利算法模板 匈牙利算法:https://blog.csdn.net/sunny_hun/article/details/80627351 #inc ...

  8. The class cn.itcast.web.common.util.UtilFuns specified in TLD for the function selffn:htmlNewline cannot be found: cn.itcast.web.common.util.UtilFuns

    我的一个Util方法的包名更改了,运行时候报这个错误.找到tld文件,把包名重新改为我改的名字就好使了.

  9. CentOS7+Nginx+多个Tomcat配置

    转载自:https://blog.csdn.net/name_chc/article/details/73332272:亲测可用,加了一些注释: 配置多个tomcat转发 另附上tomcat启动慢的解 ...

  10. SPSS—非线性回归(模型表达式)案例解析

    非线性回归过程是用来建立因变量与一组自变量之间的非线性关系,它不像线性模型那样有众多的假设条件,可以在自变量和因变量之间建立任何形式的模型    非线性,能够通过变量转换成为线性模型——称之为本质线性 ...