why php7 throw Fatal error: Allowed memory size of xx bytes exhausted (tried to allocate xx bytes)

27 篇文章 0 订阅
10 篇文章 0 订阅

用swoole 写的协程 server能做到高并发,但这有一个问题必须考虑的,多个协程跑在一个进程内,某个协程把所有的内存吃光了,

其它协程怎么办?这个进程会怎么处理?

 

首先不要管协程这么一回事,php最初设计就是一个脚本引擎,目前php版本实现的是,遇到 内存不足,不是一个 E_RECOVERABLE_ERROR,直接就 调用shutdown 函数了。

当swoole扩展引入协程概念时,还是跑在这个脚本引擎上,

一个协程吃光内存  --触发-->   脚本shutdown  --导致-->   进程内所有资源被回收(包括其它协程)

<?php
register_shutdown_function(function() {
    echo "register_shutdown_function\n";
});

$var = 'clwu';
try {
    new aa;
    $var = @str_repeat($var, 1024*1024*1024*1024);
} catch (\Throwable $e) {
    echo 'OOM',PHP_EOL;
}

上面的实验代码中,new aa 找不到这个类,php 可以catch 到这个异常,但下一行 str_repeat($var, 1024*1024*1024*1024) 会吃光所有内存,抛出一个 php 没有catch 的致命错误:

1)为什么 new aa 找不到这个类抛出的异常可以 catch ?

因为 new aa 是转换成执行php脚本引擎的代码,引擎逻辑有 判断 找不到这个类就 HANDLE_EXCEPTION()

 

2)为什么 str_repeat($var, 1024*1024*1024*1024) 吃光内存的异常没有 catch 呢?因为 php 脚本引擎的逻辑就没有写要去检测有没有异常抛出

php脚本引擎把 str_repeat 转换为一个可以 FAST CALL 的外部函数调用(底层libc库的原生代码),脚本引擎在调用完这个函数时,是执行

ZEND_VM_NEXT_OPCODE()

而不是

ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION()

,see 脚本引擎的设计时就不知道要怎么处理 外部资源的问题。目前php版本的实现是抛出一个致命的错误然后脚本中止。

 

了解了问题的根源,就有了问题的解决方案了,我不要改动 php的源码,因为到时 服务器自动更新到新版本php时又会覆盖我的改动,facebook自己维护的HHVM就不能很好的跟上生态。

还是要自己在协程的最开始主动用 memory_get_usage() 检查进程的内存是否还足够,如果不足够就 拒绝服务,以免把其它协程给坑了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值