• 技术文章 >php教程 >php手册

    win2003使用preg_match_all导致apache崩溃解决办法

    2016-06-13 09:57:09原创597

    本文章来给大家介绍在win2003使用preg_match_all导致apache崩溃解决办法,有碰到此类问题的朋友可进入参考参考。

    Apache/2.2.9 (Win32) + PHP/5.2.17,在使用正则表达式 preg_match_all (如 preg_match_all("/ni(.*?)wo/", $html, $matches);)进行分析匹配比较长的字符串 $html 时(大于10万字节,一般用于分析采集回来的网页源码),Apache服务器会崩溃自动重启。

    在Apache错误日志里有这样的提示:

    [Thu Apr 11 18:31:31 2013] [notice] Parent: child process exited with status 128 -- Restarting.
    [Thu Apr 11 18:31:31 2013] [notice] Apache/2.2.9 (Win32) PHP/5.2.17 configured -- resuming normal operations
    [Thu Apr 11 18:31:31 2013] [notice] Server built: Jun 13 2008 04:04:59
    [Thu Apr 11 18:31:31 2013] [notice] Parent: Created child process 2964
    [Thu Apr 11 18:31:31 2013] [notice] Disabled use of AcceptEx() WinSock2 API
    [Thu Apr 11 18:31:31 2013] [notice] Child 2964: Child process is running
    [Thu Apr 11 18:31:31 2013] [notice] Child 2964: Acquired the start mutex.
    [Thu Apr 11 18:31:31 2013] [notice] Child 2964: Starting 350 worker threads.
    [Thu Apr 11 18:31:31 2013] [notice] Child 2964: Listening on port 80.

    经过查阅Apache官方以及论坛资料后,发现win平台下用正则 preg_match_all 或preg_match 分析比较长的字符串时,导致apache崩溃重启的原因是windows平台下默认分配的线程堆栈空间 ThreadStackSize 太小导致的。 win32默认只有256KB,而在 linux下默认值是 8M,这就是为什么同样的程序在 linux平台下正常,而在 win平台下不正常的原因。

    根据PCRE library的官方说明:256 KB 的堆栈空间对应的pcre.recursion_limit大小应该不超过524。
    Here is a table of safe values of pcre.recursion_limit for a variety of executable stack sizes:
    下面就是一张Stacksize和pcre.recursion_limit对应的建议安全值,超过这个数值就极有可能发生堆栈溢出,apache crash:

    Stacksize pcre.recursion_limit
    64 MB 134217
    32 MB 67108
    16 MB 33554
    8 MB 16777
    4 MB 8388
    2 MB 4194
    1 MB 2097
    512 KB 1048
    256 KB 524
    如果你没有调整堆栈大小,就必须在使用正则的PHP页面最开头加入:

    ini_set("pcre.recursion_limit", "524"); // PHP default is 100,000.
    ?>

    查看具体的错误可以使用下面的代码:

    代码如下 复制代码
    $resultsArray = preg_match_all("/table.*?/isU", $html, $contents);
    if ($resultsArray === 0){
    echo get_pcre_err();
    }
    function get_pcre_err(){
    $pcre_err = preg_last_error(); // PHP 5.2 and above.
    if ($pcre_err === PREG_NO_ERROR) {
    $msg = 'Successful non-match.';
    } else {
    // preg_match error!
    switch ($pcre_err) {
    case PREG_INTERNAL_ERROR:
    $msg = 'PREG_INTERNAL_ERROR';
    break;
    case PREG_BACKTRACK_LIMIT_ERROR:
    $msg = 'PREG_BACKTRACK_LIMIT_ERROR';
    break;
    case PREG_RECURSION_LIMIT_ERROR:
    $msg = 'PREG_RECURSION_LIMIT_ERROR';
    break;
    case PREG_BAD_UTF8_ERROR:
    $msg = 'PREG_BAD_UTF8_ERROR';
    break;
    case PREG_BAD_UTF8_OFFSET_ERROR:
    $msg = 'PREG_BAD_UTF8_OFFSET_ERROR';
    break;
    default:
    $msg = 'Unrecognized PREG error';
    break;
    }
    }
    return($msg);
    }

    对于正则的修饰符 isU 说明:
    i: 表示in-casesensitive,即大小写不敏感
    s: PCRE_DOTALL,表示点号可以匹配换行符。
    U: 表示PCRE_UNGREEDY,表示非贪婪,相当于perl/python语言的.*?,在匹配过程中,对于.*正则,一有匹配立即执行,而不是等.*搜索了所有字符再一一返回
    在使用正则表达式时,我们应该尽量避免递归调用,递归容易导致堆栈溢出。比如:
    //isU 就会发生错误,而使用 //i 就正常。


    那么如何增加win平台下 ThreadStackSize 的大小呢? 在apache的配置文件 httpd.conf 里启用 “Include conf/extra/httpd-mpm.conf”(删除前面的注释#),然后在 httpd-mpm.conf 文件里的 mpm_winnt_module 配置模块里设置 “ThreadStackSize 8400000”即可(大约8M)。

    代码如下 复制代码



    ThreadStackSize 8400000
    ThreadsPerChild 200
    MaxRequestsPerChild 10000
    Win32DisableAcceptEx

    这里需要注意的是,32位的Apache程序只能最多使用大约2GB内存空间! 因此,ThreadStackSize 和ThreadsPerChild 的值相乘后(8M * 200)不应该超过2G,否则无法启动apache,出现的错误日志如下:
    [Thu Apr 11 20:02:45 2013] [crit] (OS 8)存储空间不足,无法处理此命令。 : Child 4832: _beginthreadex failed. Unable to create all worker threads. Created 212 of the 220 threads requested with the ThreadsPerChild configuration directive.
    通过上面的提示,飘易可以告诉大家的是在我的这台服务器上,当线程堆栈大小设为8M时,我可以设置的线程数最多是212个。

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    上一篇:php错误提示:Call-time pass-by-reference has been deprecated 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • PHP+DBM的同学录程序(2)_php基础• 从一个不错的留言本弄的mysql数据库操作类• 一个php作的文本留言本的例子(三)_php基础• Windows下PHP5和Apache的安装与配置_php基础• 日常整理PHP中简单的图形处理(经典)
    1/1

    PHP中文网