html5中文学习网

您的位置: 首页 > 网络编程 > PHP编程 » 正文

PHPer请手动释放你的资源_PHP教程_编程技术

[ ] 已经帮助:人解决问题

  我从来不认为这个问题是个问题, 直到昨天.xrVHTML5中文学习网 - HTML5先行者学习网

  昨天晚上的时候, 我提交了一个RFC, 关于引入finally到PHP, 实现这个功能的出发点很简单, 因为我看见不少人的需求, 另外还有就是Stas说, 一直只看到讨论, 没看到有人实现. 于是我就给实现了.xrVHTML5中文学习网 - HTML5先行者学习网

  发到邮件组以后, 一个开发组的同学Nikita Popov(nikic), 表示强烈反对这个RFC, 当然最初的论点他说了很多, 最后我们在线讨论的时候, 他表达了一个他的观点:xrVHTML5中文学习网 - HTML5先行者学习网

  “PHP在请求结束后会释放所有的资源, 所以我们没有必要调用fclose,或者mysql_close来释放资源, PHP会替我们做”xrVHTML5中文学习网 - HTML5先行者学习网

  并且他表示, 他从来都不会调用fclose, 认为fclose的存在只是为了继承C函数族.xrVHTML5中文学习网 - HTML5先行者学习网

  我很惊讶, 我也不知道还有多少人是和他一样的想法, 所以我决定写这篇文章.xrVHTML5中文学习网 - HTML5先行者学习网

  在PHP5.2以前, PHP使用引用计数(Reference count)来做资源管理, 当一个zval的引用计数为0的时候, 它就会被释放. 虽然存在循环引用(Cycle reference), 但这样的设计对于开发Web脚本来说, 没什么问题, 因为Web脚本的特点和它追求的目标就是执行时间短, 不会长期运行. 对于循环引用造成的资源泄露, 会在请求结束时释放掉. 也就是说, 请求结束时释放资源, 是一种部补救措施(backup).xrVHTML5中文学习网 - HTML5先行者学习网

  然而, 随着PHP被越来越多的人使用, 就有很多人在一些后台脚本使用PHP, 这些脚本的特点是长期运行, 如果存在循环引用, 导致引用计数无法及时释放不用的资源, 则这个脚本最终会内存耗尽退出.xrVHTML5中文学习网 - HTML5先行者学习网

  所以在PHP5.3以后, 我们引入了GC, 也就是说, 我们引入GC是为了解决用户无法解决的问题.xrVHTML5中文学习网 - HTML5先行者学习网

  这个是历史, 我简单介绍下, 现在让我们回头来看开头的问题, 是不是因为PHP会在请求结束后释放所有的资源, 于是我们就可以不用手动释放呢?xrVHTML5中文学习网 - HTML5先行者学习网

  看一个例子:xrVHTML5中文学习网 - HTML5先行者学习网

  Mysql最大连接数(mysql.max_connections)xrVHTML5中文学习网 - HTML5先行者学习网

<?php
    $db = mysql_connect() ;
    $resut = mysql_query();
    // process result...
    usleep(500);
 
    //mysql_close($db); let's say, you didn't call to this
 
    // other logic, assuming it costs 5s
    sleep(5);
 
    exit(0); //finish
xrVHTML5中文学习网 - HTML5先行者学习网

 xrVHTML5中文学习网 - HTML5先行者学习网

  上面的例子, 我们会保持一个和Mysql的连接5秒钟, 这样的脚本对于一般的应用来说没有关系, 但是对于一个请求量很大的脚本来说, 会导致一个致命问题:xrVHTML5中文学习网 - HTML5先行者学习网

  比如一个繁忙的应用, 每秒要处理来自用户的1000个请求, 那么5秒钟请求多少个? 5 * 1000 = 5000, 而Mysql有最大连接数限制(mysql.max_connections), 这个数字一般不超过2000, 默认的会更低:(mysql.max_connections),xrVHTML5中文学习网 - HTML5先行者学习网

  那么, 这样代码会导致你的应用, 根本无法正常提供服务. 而如果我们在对Mysql的处理完成后就关闭这个连接, 那么就不会触发这个问题.xrVHTML5中文学习网 - HTML5先行者学习网

  而我们在实践中, 遇到过一个更加实际的问题, 看下面的例子:xrVHTML5中文学习网 - HTML5先行者学习网

<?php
$mmc = new Memcached();
$mysql = mysql_connect();
//process
mysql_close($mysql);
$mmc->close();
xrVHTML5中文学习网 - HTML5先行者学习网

 xrVHTML5中文学习网 - HTML5先行者学习网

  这是一个真实的教训, 代码如上面所示, 突然有一天我们的Mysql出现了问题, 导致连接Mysql的耗时增大, 然后就导致, 一个脚本对Memcached连接占用过长, 最后Memcache因为连接数太多, 就拒绝服务了..xrVHTML5中文学习网 - HTML5先行者学习网

  所以, 我们一定要让连接代价最高的资源, 最先初始化.xrVHTML5中文学习网 - HTML5先行者学习网

  系统最大句柄 (/proc/sys/fs/file-max)xrVHTML5中文学习网 - HTML5先行者学习网

  这个很简单, 如果你持续打开句柄, 而不释放, 那么你有可能触发系统最大句柄限制, 对于进程来说, 自己还有进程可打开句柄数限制(ulimit -n).xrVHTML5中文学习网 - HTML5先行者学习网

  系统调用是昂贵的(System call is expensive)xrVHTML5中文学习网 - HTML5先行者学习网

  PHP之所以会在请求结束后正确的释放掉所有的资源, 内存, 这是因为当我们在脚本中使用新的内存的时候, PHP会向OS申请一大块内存(ZEND_MM_SEG_SIZE大小), 然后分给你你需要的合适的一块小内存.xrVHTML5中文学习网 - HTML5先行者学习网

  当你不使用这块小内存的时候, PHP也不会返还给OS, 而是保留下来给后续的处理使用.xrVHTML5中文学习网 - HTML5先行者学习网

  我们知道, malloc(3)会导致系统调用(brk(2))(当然也可能是mmap, 我们此处不考虑这个细节, thanks to 华裔), 而系统调用是昂贵的.xrVHTML5中文学习网 - HTML5先行者学习网

  所以, 如果你使用完了资源不及时释放, 那么后续的逻辑如果请求内存, PHP发现之前申请的一大块内存已经分光了, 它就只好再次向OS发起malloc调用, 得到一块新的大内存. 并且它还需要对这个大内存做一些标记处理..xrVHTML5中文学习网 - HTML5先行者学习网

  而如果你使用完资源, 及时释放的话, 那么下次脚本申请内存的时候, 你之前归还的内存块就可以被重复利用, 那么也许你的整个脚本只需要和OS申请一次内存.xrVHTML5中文学习网 - HTML5先行者学习网

  内存峰值(Memory peak usage)xrVHTML5中文学习网 - HTML5先行者学习网

  这个和上面的有一定的关系, 当你使用完资源就释放, 然后后续又使用这样的资源. 那么PHP的内存占用会是:xrVHTML5中文学习网 - HTML5先行者学习网

  资源+1 -> 资源-1 -> 资源+1 -> 资源-1 (峰值是1)xrVHTML5中文学习网 - HTML5先行者学习网

  而如果你是等到PHP请求结束再释放:xrVHTML5中文学习网 - HTML5先行者学习网

  资源+1 -> 资源 + 1 …. -> 资源 -1 -> 资源 – 1 (峰值是2)xrVHTML5中文学习网 - HTML5先行者学习网

  也就说, 一个良好的编写的脚本可能要比一个瞎写的脚本, 要省很多峰值内存..xrVHTML5中文学习网 - HTML5先行者学习网

  考虑一个极端情况, 对一个很繁忙的服务器来说, 比如有10个PHP进程, 每个PHP进程最大1G内存, 而服务器只有8G内存.xrVHTML5中文学习网 - HTML5先行者学习网

  结论 (conclusion)xrVHTML5中文学习网 - HTML5先行者学习网

  结论很明显, 我开头也说过了, 我从来不认为这个是个问题.xrVHTML5中文学习网 - HTML5先行者学习网

  这里说一句, 如果你买了一本PHP的书, 它告诉你: “不用在PHP主动释放资源, 因为PHP会帮你释放”的话, 我建议你, 烧了它.xrVHTML5中文学习网 - HTML5先行者学习网

xrVHTML5中文学习网 - HTML5先行者学习网
xrVHTML5中文学习网 - HTML5先行者学习网
(责任编辑:)
推荐书籍
推荐资讯
关于HTML5先行者 - 联系我们 - 广告服务 - 友情链接 - 网站地图 - 版权声明 - 人才招聘 - 帮助