网站建设
  简约型网页设计套餐998
  实惠型网站建设套餐2580
  综合型网站制作套餐4980
  网站改版与网站维护
  行业网站建设方案
  大型网站建设解决方案
  企业网站建设流程
  帝网科技网站设计与网站制作
建站FAQ
·网站空间问题解答
·企业邮箱问题解答
 
酷站欣赏
·房产酷站(379)
·综合门户(8 9)
·建筑装饰(603)
·手机通讯(354)
·生活购物(376)
·医疗保健(199)
·文化摄影(602)
·休闲体育(399)
>>更多酷站欣赏
网站优化
·Google(谷歌)优化   ·百度(BaiDu)优化
·雅虎(Yahoo)优化    ·Alexa排名优化   
·Google AdSense   ·DMOZ目录提交  
建站知识
·网站建设知识·网站名词解释·网站运营知识
·网络营销知识·搜索引擎知识·实用技术文摘
网站推广
百度网站推广 google网站推广
搜狐网站推广 网易网站推广
新浪网站推广   雅虎网站推广
  您当前位置: 当前位置:帝网科技 >> web开发 >> PHP专栏 >> 浏览文章
 
 
深入探讨PHP中的内存管理问题
作者:袁袁整理 来源:帝网科技 日期:2008年09月13日 点击数:


摘要:内存管理对于长期运行的程序,例如服务器守护程序,是相当重要的影响;因此,理解PHP是如何分配与释放内存的对于创建这类程序极为重要。本文将重点探讨PHP的内存管理问题。
 

一、内存

在PHP中,填充一个字符串变量相当简单,这只需要一个语句"<?php$str='helloworld';?>"即可,并且该字符串能够被自由地修改、拷贝和移动。而在C语言中,尽管你能够编写例如"char*str="helloworld";"这样的一个简单的静态字符串;但是,却不能修改该字符串,因为它生存于程序空间内。为了创建一个可操纵的字符串,你必须分配一个内存块,并且通过一个函数(例如strdup())来复制其内容。

  {
 char*str;
 str=strdup("helloworld");
 if(!str){
fprintf(stderr,"Unabletoallocatememory!");
 }
}
由于后面我们将分析的各种原因,传统型内存管理函数(例如malloc(),free(),strdup(),realloc(),calloc(),等等)几乎都不能直接为PHP源代码所使用。

二、释放内存

在几乎所有的平台上,内存管理都是通过一种请求和释放模式实现的。首先,一个应用程序请求它下面的层(通常指"操作系统"):"我想使用一些内存空间"。如果存在可用的空间,操作系统就会把它提供给该程序并且打上一个标记以便不会再把这部分内存分配给其它程序。
当应用程序使用完这部分内存,它应该被返回到OS;这样以来,它就能够被继续分配给其它程序。如果该程序不返回这部分内存,那么OS无法知道是否这块内存不再使用并进而再分配给另一个进程。如果一个内存块没有释放,并且所有者应用程序丢失了它,那么,我们就说此应用程序"存在漏洞",因为这部分内存无法再为其它程序可用。

在一个典型的客户端应用程序中,较小的不太经常的内存泄漏有时能够为OS所"容忍",因为在这个进程稍后结束时该泄漏内存会被隐式返回到OS。这并没有什么,因为OS知道它把该内存分配给了哪个程序,并且它能够确信当该程序终止时不再需要该内存。

而对于长时间运行的服务器守护程序,包括象Apache这样的web服务器和扩展php模块来说,进程往往被设计为相当长时间一直运行。因为OS不能清理内存使用,所以,任何程序的泄漏-无论是多么小-都将导致重复操作并最终耗尽所有的系统资源。

现在,我们不妨考虑用户空间内的stristr()函数;为了使用大小写不敏感的搜索来查找一个字符串,它实际上创建了两个串的各自的一个小型副本,然后执行一个更传统型的大小写敏感的搜索来查找相对的偏移量。然而,在定位该字符串的偏移量之后,它不再使用这些小写版本的字符串。如果它不释放这些副本,那么,每一个使用stristr()的脚本在每次调用它时都将泄漏一些内存。最后,web服务器进程将拥有所有的系统内存,但却不能够使用它。

你可以理直气壮地说,理想的解决方案就是编写良好、干净的、一致的代码。这当然不错;但是,在一个象PHP解释器这样的环境中,这种观点仅对了一半。

三、错误处理

为了实现"跳出"对用户空间脚本及其依赖的扩展函数的一个活动请求,需要使用一种方法来完全"跳出"一个活动请求。这是在Zend引擎内实现的:在一个请求的开始设置一个"跳出"地址,然后在任何die()或exit()调用或在遇到任何关键错误(E_ERROR)时执行一个longjmp()以跳转到该"跳出"地址。

尽管这个"跳出"进程能够简化程序执行的流程,但是,在绝大多数情况下,这会意味着将会跳过资源清除代码部分(例如free()调用)并最终导致出现内存漏洞。现在,让我们来考虑下面这个简化版本的处理函数调用的引擎代码:

  voidcall_function(constchar*fname,intfname_lenTSRMLS_DC){
 zend_function*fe;
 char*lcase_fname;
 /*PHP函数名是大小写不敏感的,
 *为了简化在函数表中对它们的定位,
 *所有函数名都隐含地翻译为小写的
 */
 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_arrayTSRMLS_CC);
 }else{
php_error_docref(NULLTSRMLS_CC,E_ERROR,"Calltoundefinedfunction:%s()",fname);
 }
 efree(lcase_fname);
}


当执行到php_error_docref()这一行时,内部错误处理器就会明白该错误级别是critical,并相应地调用longjmp()来中断当前程序流程并离开call_function()函数,甚至根本不会执行到efree(lcase_fname)这一行。你可能想把efree()代码行移动到zend_error()代码行的上面;但是,调用这个call_function()例程的代码行会怎么样呢?fname本身很可能就是一个分配的字符串,并且,在它被错误消息处理使用完之前,你根本不能释放它。

注意,这个php_error_docref()函数是trigger_error()函数的一个内部等价实现。它的第一个参数是一个将被添加到docref的可选的文档引用。第三个参数可以是任何我们熟悉的E_*家族常量,用于指示错误的严重程度。第四个参数(最后一个)遵循printf()风格的格式化和变量参数列表式样。
四、Zend内存管理器

在上面的"跳出"请求期间解决内存泄漏的方案之一是:使用Zend内存管理(ZendMM)层。引擎的这一部分非常类似于操作系统的内存管理行为-分配内存给调用程序。区别在于,它处于进程空间中非常低的位置而且是"请求感知"的;这样以来,当一个请求结束时,它能够执行与OS在一个进程终止时相同的行为。也就是说,它会隐式地释放所有的为该请求所占用的内存。图1展示了ZendMM与OS以及PHP进程之间的关系。

  相关文章
 
·如何在PHP开启gzip页面压缩实例正文分
·如何正确运用PHP json_encode函数进行
·PHP下载断点续传的代码正文分析错误
·PHP取得客户端IP地址代码正文分析错误
·PHP判断用户IP来路的一个方法正文分析
·PHP+mysql分页代码正文分析错误
·php去除HTML标记正文分析错误
·php轻松快速缓存全站正文分析错误
·php多语言网站解决方案正文分析错误
·php图片验证码函数正文分析错误
·PHP初学者常见问题集(21问答)正文分
·分享PHP技术开发技巧正文分析错误
·cURL库功能简介:抓取网页 POST数据及
·PHP常用函数:过滤HTML字符串正文分析
·php fscanf()函数使用方法详解正文分析
·和php有关的几种常见安全详解正文分析
·php连接mysql出现乱码解决办法正文分析
·PHP非常简单的使用模板制作静态页面正
·非常简单PHP缩略图生成程序源代码正文
·无法载入 mcrypt 扩展,请检查 PHP 配置
 
 

公司环境 | 合作伙伴 | 人才招聘 | 付款方式 | 关于我们

地址:广州市天河区中山大道中120号D805 电话:020-82529556 传真:020-82529556
广州帝网网络科技有限公司 版权所有 粤ICP备08119341号