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

探讨Swoole协程服务器在高并发场景下面临的内存管理挑战,特别是单个协程占用过多内存导致的问题及解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用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() 检查进程的内存是否还足够,如果不足够就 拒绝服务,以免把其它协程给坑了。

### OpenCV中由于内存不足导致的`cv::Exception`异常问题分析 在OpenCV中,当出现`cv::Exception`异常并提示`Insufficient memory`时,通常表明程序尝试分配的内存超出了系统可用的内存资源[^1]。这种问题可能由多种原因引起,包括但不限于内存泄漏、数据结构过大或硬件资源限制。 以下是对该问题的详细分析及解决方案: #### 1. 内存分配失败的原因 内存分配失败可能是由于以下几种情况引起的: - **内存泄漏**:程序运行过程中未能正确释放已分配的内存,导致可用内存逐渐减少[^1]。 - **数据结构过大**:处理的数据量(如图像尺寸或矩阵大小)超出系统能够支持的范围[^4]。 - **硬件资源限制**:系统可用内存不足,例如在嵌入式设备或虚拟环境中运行时,物理内存和交换空间有限[^5]。 #### 2. 解决方案 以下是针对上述问题的具体解决方法: ##### (1) 检查并修复内存泄漏 确保所有动态分配的内存都已正确释放。可以使用工具(如Valgrind或Visual Studio的诊断工具)检测内存泄漏。例如,在C++中使用`cv::Mat`对象时,应避免手动管理内存,尽量依赖RAII机制自动释放资源。 ##### (2) 减少数据规模 如果数据结构过大,可以通过以下方式优化: - **缩小图像尺寸**:在加载图像时,使用`cv::resize`函数将图像缩放到更小的尺寸[^5]。 - **降低图像质量**:对于某些应用场景,可以接受较低分辨率或压缩率的图像。 - **分块处理**:将大图像分割为多个小块分别处理,最后合并结果。 示例代码: ```python import cv2 # 缩小图像尺寸 image = cv2.imread('large_image.jpg') resized_image = cv2.resize(image, (0, 0), fx=0.5, fy=0.5) cv2.imwrite('resized_image.jpg', resized_image) ``` ##### (3) 增加系统可用内存 - **增加物理内存**:升级硬件配置以提供更多的RAM。 - **启用虚拟内存**:调整操作系统中的虚拟内存设置,允许更大的交换文件[^5]。 - **优化内存使用**:关闭不必要的后台程序,释放更多内存资源。 ##### (4) 使用更高效的算法或模型 在某些情况下,选择更轻量级的算法或模型可以显著减少内存消耗。例如,使用YOLOv8n代替YOLOv8l进行目标检测[^5]。 示例代码: ```python from ultralytics import YOLO # 加载轻量级模型 model = YOLO("yolov8n.pt") results = model.train(data="class.yaml", imgsz=640, epochs=20, batch=4, device=0) ``` ##### (5) 分布式计算 对于大规模数据处理任务,可以考虑使用分布式计算框架(如Spark或Dask)将任务分配到多台机器上执行[^4]。 #### 3. 示例场景与代码 以下是一个具体的场景:训练分类器时遇到内存不足问题。 ##### 场景描述 在使用OpenCV自带的`haartraining`函数训练分类器时,当图像尺寸从20x20增大到80x86后,出现内存不足错误。 ##### 解决方法 - 减少训练样本数量。 - 将图像尺寸缩放到较小的尺寸。 - 增加系统内存或优化内存分配。 示例代码: ```python import cv2 # 缩小图像尺寸 def preprocess_images(image_paths, target_size=(40, 46)): processed_images = [] for path in image_paths: image = cv2.imread(path, cv2.IMREAD_GRAYSCALE) resized_image = cv2.resize(image, target_size) processed_images.append(resized_image) return processed_images # 调用预处理函数 processed_data = preprocess_images(image_paths, target_size=(40, 46)) ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值