,$str这个字符串变量可以被自由的修改与复制等。这一切在C语言里看起来都是不可能的事情,我们用#char *p = "hello";#来定义一个字符串,但它是常量,是不能被修改的,如果你用p[1]='c';来修改" />
设为首页 - 加入收藏
您的当前位置:主页 > 网络编程 > PHP > 正文

在PHP内核探索:Zend内存管理器的方法

来源:网络收集 点击数: 时间:2016-08-09

在PHP里,我们可以定义字符串变量,比如 <?php $str="#"; ?>,$str这个字符串变量可以被自由的修改与复制等。这一切在C语言里看起来都是不可能的事情,我们用#char *p = "hello";#来定义一个字符串,但它是常量,是不能被修改的,如果你用p[1]='c';来修改这个字符串会引发段错误(Gcc,c99),为了修改C语言里的字符串常量,我们往往需要定义字符串数组。为了得到一个能够让我们自由修改的字符串,我们往往需要用strdup函数来复制一个字符串出来。

{
	char *p = "hello world";
	// p[0] = 'a'; 如果这么做,就等着运行时段错误吧。
	char *str;
	str = strdup(p);
	str[0] = 'a'; //这时就能自由修改了。
}

在PHP内核中,大多数情况下都不应改直接使用C语言中自带着malloc、free、strdup、realloc、calloc等操作内存的函数,而应使用内核提供的操作内存的函数,这样可以由内核整体统一的来管理内存。

Free the Mallocs

每个平台操作内存的方式都是差不多的有两个方面,一负责申请,二负责释放。如果应用程序向系统申请内存,系统便会在内存中寻找还没有被使用的地方,如果有合适的,便分配给这个程序,并标记下来,不再给其它的程序了。如果一个内存块没有释放,而所有者应用程序也永远不再使用它了。那么,我们就称其为"内存泄漏",那么这部分内存就无法再为其它程序所用了。

在一个典型的客户端应用程序中,偶尔的小量的内存泄漏是可以被操作系统容忍的,因为在进程结束后该泄漏内存会被返回给OS。这并没有什么高科技含量,因为OS知道它把该内存分配给了哪个程序,并且它能够在一个程序结束后把这些内存给回收回来。

但是,世界总是不缺乏特例!对于一些需要长时间运行的程序,比如像Apache这样的web服务器以及它的php模块来说,都是伴随着操作系统长时间运行的,所以OS在很长一段时间内不能主动的回收内存,从而导致这个程序的每一个内存泄漏都会促进量变到质变的进化,最终引起严重的内存泄漏错误,使系统的资源消耗殆尽。现在,我们来在C语言中故意错误的模拟一下PHP的stristr()函数为例,为了使用大小写不敏感的方式来搜索一个字符串,我们需要创建两个辅助的字符串,它们分别是被查找字符串和待查找字符串的小写化副本,然后由这两个副本来帮助我们来完成这次搜索。如果我们在执行这个函数后不释放这些副本占用的资源,那么每一次stristr函数都将是对内存的一次永远的侵占,最终导致这个函数占用了所有的系统内存,而没有实际意义!

大多数人提出来的理想的解决方案是:书写优秀,整洁并且风格一致的代码,这当然是毫无疑问的。但是在PHP扩展开发这样的底层环境中,这并不能解决全部的问题。比如,你需要自己保证在层层嵌套调用中对某块内存的使用都是正确的,且会及时释放的。

错误处理

为了实现从用户端(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) == FAILURE)
    {
        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多种图片格式的简单上传的方法
下一篇:没有了
栏目分类

A3站长网 站长网 站长网技术网 站长教程网 织梦CMS教程 织梦模板 帝国CMS模板 联系QQ:26991496 邮箱:26991496@qq.com

A3站长网:欢迎您!谢谢您的访问...

Top