小知识:win2003下PHP使用preg_match_all导致apache崩溃问题的解决方法

小编的平台是windows server 2003(32位系统) + 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语言的.*?,在匹配过程中,对于.*正则,一有匹配立即执行,而不是等.*搜索了所有字符再一一返回

    在使用正则表达式时,我们应该尽量避免递归调用,递归容易导致堆栈溢出。比如:

/<table((?!<table).)*?<\/a>/isU 就会发生错误,而使用 /<table.*?<\/a>/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

</IfModule>

    这里需要注意的是,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个。

声明: 猿站网有关资源均来自网络搜集与网友提供,任何涉及商业盈利目的的均不得使用,否则产生的一切后果将由您自己承担! 本平台资源仅供个人学习交流、测试使用 所有内容请在下载后24小时内删除,制止非法恶意传播,不对任何下载或转载者造成的危害负任何法律责任!也请大家支持、购置正版! 。本站一律禁止以任何方式发布或转载任何违法的相关信息访客发现请向站长举报,会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。本网站的资源部分来源于网络,如有侵权烦请发送邮件至:2697268773@qq.com进行处理。
建站知识

小知识:Flume环境部署和配置详解及案例大全

2023-3-17 14:41:49

建站知识

小知识:LNMP服务器环境配置 (linux+nginx+mysql+php)

2023-3-17 14:56:23

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索