专栏首页PHP饭米粒PHP内存分配超过限制的退出流程

PHP内存分配超过限制的退出流程

我们知道,在PHP的世界里,如果我们要申请一块内存 ,但是没有申请到,那么就会导致fatal级别的错误。我们来测试下:

<?php

ini_set('memory_limit','1M');

$str = str_repeat('a', 2 * 1024 * 1024);

执行结果如下:

[root@a896c4eb1fc4 library]# php oom.php
PHP Fatal error:  Allowed memory size of 2097152 bytes exhausted at /root/php-src/Zend/zend_string.h:144 (tried to allocate 2097184 bytes) in /root/codeDir/phpCode/library/oom.php on line 5

Fatal error: Allowed memory size of 2097152 bytes exhausted at /root/php-src/Zend/zend_string.h:144 (tried to allocate 2097184 bytes) in /root/codeDir/phpCode/library/oom.php on line 5
[root@a896c4eb1fc4 library]#

可以看到,这里抛出了fatal的错误。

可能有小伙伴会觉得很正常,既然内存用完了,就应该报错,然后终止程序的执行才对。况且,大部分的PHP程序都是FPM的模型,就算这个PHP进程挂了,也不会影响后续的请求。但是,这对于基于CLI的常驻内存的PHP程序就是致命的了,一旦超过了内存限制,就会导致整个服务挂了,哪怕这次内存申请是很不重要的,也会导致整个VM的崩溃。比如说,我想要分配一个内存,但是不确定要分配多少,所以我只能够去尝试着分配。比如说第一次尝试分配2M,第二次尝试分配1M。然而,第一次申请的内存太多了,达到了限制,直接就是fatal了,就没有后续尝试分配1M的事情了。所以,这就会导致,我们不敢百分之百的去使用内存资源,因为一旦我们不小心申请的内存超过了限制,程序就会直接奔溃,没有任何拯救的余地。

我们来打个类似的比方,我们写一个Web服务器,我们要去accept连接,但是,这个时候返回了一个Too many open files的错误码。这个时候,我们是直接让程序exit吗?还是sleep一会儿,然后再去accept连接?显然是后者。所以,我们写长生命周期的脚本,需要把内存限制往大了开。

我们现在来看一下PHP内核是如何处理内存达到限制的情况的。重点在函数zend_mm_safe_error里面:

static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap,
	const char *format,
	size_t limit,
#if ZEND_DEBUG
	const char *filename,
	uint32_t lineno,
#endif
	size_t size)
{

	heap->overflow = 1;
	zend_try {
		zend_error_noreturn(E_ERROR,
			format,
			limit,
#if ZEND_DEBUG
			filename,
			lineno,
#endif
			size);
	} zend_catch {
	}  zend_end_try();
	heap->overflow = 0;
	zend_bailout();
	exit(1);
}

在调用str_repeat时候,如果内存不够,zend_mm_safe_error就会被调用。我们发现,在这个函数里面,调用了zend_bailout(),这就会导致PHP的执行流回到php_execute_script这个函数的zend_try里面,然后,PHP脚本退出执行。

所以,我们发现,只要有一次申请的PHP内存累积到了我们设置的限制,就没有任何拯救的余地了,进程直接退出了。

----------伟大的分割线-----------

本文由 coding huang 授权 饭米粒 发布,转载请注明本来源信息和以下的二维码(长按可识别二维码关注)

本文分享自微信公众号 - PHP饭米粒(phpfamily),作者:桶哥

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-07-13

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 技术分享 | MongoDB 一次排序超过内存限制的排查

    某次在客户现场处理一起APP业务中页面访问异常的问题,该页面直接是返回一行行硕大的报错代码,错误大概如下所示:

    拓荒者
  • 技术分享 | MongoDB 一次排序超过内存限制的排查 setParameter:

    某次在客户现场处理一起APP业务中页面访问异常的问题,该页面直接是返回一行行硕大的报错代码,错误大概如下所示:

    拓荒者
  • think-queue 解析上

    分析之前请大家务必了解消息队列的实现 如果不了解请先阅读下: 有赞消息队列设计 去哪儿网消息队列设计

    李昊天
  • PHP7内核CGI与FastCGI详解

    CGI:是 Web Server 与 Web Application 之间数据交换的一种协议。 FastCGI:同 CGI,是一种通信协议,但比 CGI 在效...

    砸漏
  • think-queue 解析上

    tp5的消息队列是基于database redis 和tp官方自己实现的 Topthink

    李昊天
  • 为什么Python Web流行度不如PHP?

    引用 @Rio 的看法:我觉得 Python 不会像 PHP 那样流行,根本原因在于部署的难易程度。 PHP 从语言层面上讲几乎是一无是处,具体实现的质量也乏善...

    小小科
  • PHP-FPM多方面调优策略

    FPM(FastCGI 进程管理器)用于替换 PHP FastCGI 的大部分附加功能,对于高负载网站是非常有用的。比方说: 支持平滑停止/启动的高级进程管理功...

    憧憬博客
  • 如何在Centos系统上安装Wordpress

    WordPress是一个以PHP和MySQL为平台的自由开源的博客软件和内容管理系统。WordPress具有插件架构和模板系统。Alexa排行前100万的网站中...

    信姜缘
  • 08 . Nginx状态码

    常见_youmen

扫码关注云+社区

领取腾讯云代金券