IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

memory_limit的一个bug

风雪之隅 2009-11-27 18:16:11 累计浏览 3,114 次
本机暂存

PHP 5.2x中, 由于错误的选用了zend_atoi导致 memory_limit不能设置为超过4G的值.

今天同事分享给我一个问题(thans to yanmi), 一段代码, 设置memory_limit为4096M会导致内存耗尽, 而设置4095M就不会. 奇怪的问题呵.

那是怎么回事呢?

问题的原因也很简单, 在PHPSRC/main.c中定义的memory_limit设置项的处理器OnChangeMemoryLimit中, 使用了zend_atoi来做为字符串数字化, 这个问题在PHP5.3的版本中已经修正(换成了zend_atol):

以下是代码片段:
static PHP_INI_MH(OnChangeMemoryLimit)
{
    if (new_value) {
        PG(memory_limit) = zend_atoi(new_value, new_value_length);
    } else {
        PG(memory_limit) = 1<<30;       /* effectively, no limit */
    }
    return zend_set_memory_limit(PG(memory_limit));
}

而, 顾名思义么, atoi是转成整形, 4096M是2的32次方, 发生溢出导致结果为0, zend_atoi代码如下:

以下是代码片段:
ZEND_API int zend_atoi(const char *str, int str_len)
{
    int retval;

    if (!str_len) {
        str_len = strlen(str);
    }
    retval = strtol(str, NULL, 0);
    if (str_len>0) {
        switch (str[str_len-1]) {
            case ’g’:
            case ’G’:
                retval *= 1024;
                /* break intentionally missing */
            case ’m’:
            case ’M’:
                retval *= 1024;
                /* break intentionally missing */
            case ’k’:
            case ’K’:
                retval *= 1024;
                break;
        }
    }
    return retval;
}

最后在zend_set_memory_limit的时候, 会错误的设置memory_limit为mm_heap的blok_size, 那结果就肯定远远小与你所预期的4096M了

以下是代码片段:
....
 AG(mm_heap)->limit = (memory_limit >= AG(mm_heap)->block_size) ? memory_limit : AG(mm_heap)->block_size;
...

PS, 多看别人的代码是有好处的, 今天有学会了intentionally这个单词, ^_^.

同分类推荐文章

  1. 等了十年的 Go 链式管道,终于来了:seq 让你像写 Scala 一样写 Go (2026-06-25 18:38:18)
  2. Go 实验特性详解 (2026-06-21 10:05:27)
  3. amd64 微架构级别对 Go 程序性能提升多少? (2026-06-21 09:38:49)

查看更多 后端 文章 →

建议继续学习

  1. 使用gettext来支持PHP的多语言 (累计阅读 39,270)
  2. WordPress插件开发 -- 在插件使用数据库存储数据 (累计阅读 29,164)
  3. Paypal接口详细代码(PHP版,非API接口) (累计阅读 19,408)
  4. 我的PHP,Python和Ruby之路 (累计阅读 13,149)
  5. include(“./file.php”)和include(“file.php”)区别 (累计阅读 12,789)
  6. 15个最好的免费开源电子商务平台 (累计阅读 12,541)
  7. Redis消息队列的若干实现方式 (累计阅读 12,088)
  8. 到底什么是MVC? (累计阅读 11,868)
  9. 整理了一份招PHP高级工程师的面试题 (累计阅读 11,709)
  10. Rolling cURL: PHP并发最佳实践 (累计阅读 11,488)