php内存管理

php内存处理
1、错误处理
为了实现从用户端(PHP语言中)"跳出",需要使用一种方法来完全"跳出"一个活动请求。这个功能是在内核中实现的:在一个请求的开始设置一个"跳出"地址,然后在任何die()或exit()调用或在遇到任何关键错误(E_ERROR)时执行一个longjmp()以跳转到该"跳出"地址。

void call_function(const char *fname, int fname_len TSRMLS_DC)
{
zend_function *fe;
char *lcase_fname;
/* php函数的名字是大小写不敏感的
* 我们可以在function tables里找到他们
* 保存的所有函数名都是小写的。
*/
lcase_fname = estrndup(fname, fname_len);
zend_str_tolower(lcase_fname, fname_len);

if (zend_hash_find(EG(function_table),lcase_fname, fname_len + 1, (void **)&fe) == SUCCESS)
{
zend_execute(fe->op_array TSRMLS_CC);
}
else
{
php_error_docref(NULL TSRMLS_CC, E_ERROR,"Call to undefined function: %s()", fname);
}
efree(lcase_fname);
}

当php_error_docref这个函数被调用的时候,便会触发内核中的错误处理机制,根据错误级别来决定是否调用longjmp来终止当前请求并退出call_function函数,从而efree函数便永远不会被执行了。

其实php_error_docref()函数就相当与php语言里的trigger_error()函数.它的第一个参数是一个将被添加到docref的可选的文档引用第三个参数可以是任何我们熟悉的E_*家族常量,用于指示错误的严重程度。后面的两个参数就像printf()风格的格式化和变量参数列表式样。

2、zend内存管理器
内存申请,隐式释放

3、引用计数,写时复制

引用计数
zval *helloval;
MAKE_STD_ZVAL(helloval);
ZVAL_STRING(helloval, "Hello World", 1);
zend_hash_add(EG(active_symbol_table), "a", sizeof("a"),&helloval, sizeof(zval*), NULL);
ZVAL_ADDREF(helloval); //这句很特殊,我们显式的增加了helloval结构体的refcount
zend_hash_add(EG(active_symbol_table), "b", sizeof("b"),&helloval, sizeof(zval*), NULL);

写时复制
zval *get_var_and_separate(char *varname, int varname_len TSRMLS_DC)
{
zval **varval, *varcopy;
if (zend_hash_find(EG(active_symbol_table),varname, varname_len + 1, (void**)&varval) == FAILURE)
{
/* 如果在符号表里找不到这个变量则直接return */
return NULL;
}

if ((*varval)->refcount < 2)
{
//如果这个变量的zval部分的refcount小于2,代表没有别的变量在用,return
return *varval;
}

/* 否则,复制一份zval*的值 */
MAKE_STD_ZVAL(varcopy);
varcopy = *varval;

/* 复制任何在zval*内已分配的结构*/
zval_copy_ctor(varcopy);

/* 从符号表中删除原来的变量
* 这将减少该过程中varval的refcount的值
*/
zend_hash_del(EG(active_symbol_table), varname, varname_len + 1);

/* 初始化新的zval的refcount,并在符号表中重新添加此变量信息,并将其值与我们的新zval相关联。*/
varcopy->refcount = 1;
varcopy->is_ref = 0;
zend_hash_add(EG(active_symbol_table), varname, varname_len + 1,&varcopy, sizeof(zval*), NULL);

/* 返回新zval的地址 */
return varcopy;
}

posted on 2016-12-21 11:46  面壁偷笑  阅读(194)  评论(0编辑  收藏  举报