PHP内存溢出Allowed memory size of 解决办法
以前追踪过这个问题,但是那个时候工具用的不太好,没看的这么细,这次搞的比较细,修正了偶以前的看法
.于是写小文一篇总结一下.
PHP偶尔会爆一下如下 错误Allowed memory size of xxx bytes exhausted at xxx:xxx (tried to
allocate xxx bytes)
不想看原理的,直接跳到最后看总结.
这个报错信息的意思是是说,若ini配置的memory_limit(内存限制) 大于 AG(allocated_memory),就报错
AG(allocated_memory) += rs;if (AG(memory_limit)<AG(allocated_memory)) {int php_mem_limit = AG(memory_limit);AG(allocated_memory) -= rs; if (EG(in_execution) && AG(memory_limit)+1048576 > AG(allocated_memory)){ AG(memory_limit) = AG(allocated_memory) + 1048576; if (file) {zend_error(E_ERROR,"Allowed memory size of %d bytes exhausted
at %s:%d (tried to allocate %d bytes)", php_mem_limit, file, lineno, s);} else {zend_error(E_ERROR,"Allowed memory size of %d bytes exhausted
(tried to allocate %d bytes)", php_mem_limit, s);} } else { if (file) {fprintf(stderr, "Allowed memory size of %d bytes exhausted
at %s:%d (tried to allocate %d bytes)n", php_mem_limit, file, lineno, s);} else {fprintf(stderr, "Allowed memory size of %d bytes exhausted
(tried to allocate %d bytes)n", php_mem_limit, s);} exit(1);}
}memory_limit很简单,就是PHP可用的内存..AG(allocated_memory)是什么呢?是不是已经使用的内存,恩,
我们用代码验证一下
PHP_FUNCTION(memory_get_usage) {RETURN_LONG(AG(allocated_memory));
}
这下就清晰明了,还不懂的,查php手册,看memory_get_usage的说明
到底什么时候设置AG(allocated_memory)呢,具体代码就不贴了,太繁琐,是在emalloc函数中调用了第一段
代码,看第一行代码,那里的rs就是每次tried to allocate %d bytes对应的s变量(你要申请的实际空间)
的align对齐,具体计算方法:rs = (s+7) & ~0x7,也就是必须是8的倍数,不足则补足,这样做的好处是符合
64位机器的要求,可以加速运算,例如 s =1,那么运算出来的rs =8 ,具体的,可以自己用PHP写个函数计算
(0×7是16进制写法).
总结:既然知道了怎么回事,就好解决了,在开启 –enable-memory-limit情况下,会出这个错误,把配置文
件直接设置memory_limit,或者在代码中设置ini_set(‘memory_limit’, ‘value’)都可以,省事的办法
就是设置配置文件(如php.ini)
而且建议开启–enable-memory-limit,若这个不开启,PHP的内存限制就处于”裸跑”状态,可能会出现著
名的out of memory错误.
使用脚本语言最大的好处之一就是可利用其拥有的自动垃圾回收机制(释放内存)。你不需要在使用完变
量后做任何释放内存的处理,PHP会帮你完成。
当然,我们可以按自己的意愿调用 unset() 函数来释放内存,但通常不需要这么做。
不过在PHP里,至少有一种情况内存不会得到自动释放,即便是手动调用 unset()。
问题症状
如果两个对象之间存在着相互引用的关系,如“父对象-子对象”,对父对象调用 unset() 不会释放在子
对象中引用父对象的内存(即便父对象被垃圾回收,也不行)。
有些糊涂了?我们来看下面的这段代码:
<?php
class Foo {
function __construct()
{
$this->bar = new Bar($this);
}
}class Bar {
function __construct($foo = null)
{
$this->foo = $foo;
}
}while (true) {
$foo = new Foo();
unset($foo);
echo number_format(memory_get_usage()) . "\n";
}
?>
运行这段代码,你会看到内存使用率越来越高越来越高,直到用光光。
...
33,551,616
33,551,976
33,552,336
33,552,696
PHP Fatal error: Allowed memory size of 33554432 bytes exhausted
(tried to allocate 16 bytes) in memleak.php on line 17
对大部分PHP程序员来讲这种情况不算是什么问题。
可如果你在一个长期运行的代码中使用到了一大堆相互引用的对象,尤其是在对象相对较大的情况下,内
存会迅速地消耗殆尽。
Userland解决方案
虽然有些乏味、不优雅,但之前提到的 bugs.php.net 链接中提供了一个解决方案。
这个方案在释放对象前使用一个 destructor 方法以达到目的。Destructor 方法可将所有内部的父对象
引用全部清除,也就是说可以将这部分本来会溢出的内存释放掉。
以下是“修复后”的代码:
<?php
class Foo {
function __construct()
{
$this->bar = new Bar($this);
}
function __destruct()
{
unset($this->bar);
}
}class Bar {
function __construct($foo = null)
{
$this->foo = $foo;
}
}while (true) {
$foo = new Foo();
$foo->__destruct();
unset($foo);
echo number_format(memory_get_usage()) . "\n";
}
?>
注意那个新增的 Foo::__destruct()方法,以及在释放对象前对 $foo->__destruct() 的调用。现在这
段代码解决了内存使用率一直增加的问题,这么一来,代码就可以很好的工作了。
PHP内核解决方案?
为什么会有内存溢出的发生?我对PHP内核方面的研究并不精通,但可以确定的是此问题与引用计数有关
系。
在 $bar 中引用 $foo 的引用计数不会因为父对象 $foo 被释放而递减,这时PHP认为你仍需要 $foo 对
象,也就不会释放这部分的内存……大概是这样。
这里确实可以看出我的无知,但大体意思是:一个引用计数没有递减,所以一些内存永远得不到释放。
在前面提到的 bugs.php.net 链接中我看到修改垃圾回收的过程将会牺牲极大的性能,因为我对引用计数
了解不多,所以我认为这是真的。
与其改变垃圾回收的过程,为什么不用 unset() 对内部对象做释放的工作呢?(或者在释放对象的时候
调用 __destruct()?)
也许PHP内核开发者可以在此或其他地方,对这种垃圾回收处理机制做出修改。
更新:Martin Fjordvald 在评论中提到了一个由 David Wang 为垃圾回收所写的补丁(其实它看起来更
像“一整块布”——非常巨大。详情参见此邮件结尾的CVS导出信息。)确实存在(一封邮件),并受到
了PHP内核开发成员的关注。问题是这个补丁要不要放到PHP5.3中并未得到太多支持。我觉得一个不错的
折中方案就是在 unset() 函数中调用对象中的 __destruct() 方法;
========================内存溢出解决方案
在做数据统计分析时,经常会遇到大数组,可能会发生内存溢出,这里分享一下我的解决方案。还是用例子来说明这个问题,如下:
假定日志中存放的记录数为500000条,那么解决方案如下:
ini_set(‘memory_limit’,’64M’); //重置php可以使用的内存大小为64M,一般在远程主机上是不能修改php.ini文件的,只能通过程序设置。注:在safe_mode(安全模式)下,ini_set失效
set_time_limit(600);//设置超时限制为6分钟$farr = $Uarr = $Marr = $IParr = $data = $_sub = array();
$spt = ”$@#!$”;
$root = ”/Data/webapps/VisitLog”;
$path = $dpath = $fpath = NULL;
$path = $root.”/”.date(“Y-m”,$timestamp);
$dpath = $path.”/”.date(“m-d”,$timestamp);
for($j=0;$j<24;$j++){
$v = ($j < 10) ? ”0″.$j : $j;
$gpath = $dpath.”/”.$v.”.php”;
if(!file_exists($gpath)){
continue;
} else {
$arr = file($gpath);将文件读入数组中
array_shift($arr);//移出第一个单元-》<?php exit;?>
$farr = array_merge($farr,$arr);
unset($arr);
}
}
if(empty($this->farr)){
echo ”<p><center>没有相关记录!</center></p>”;
exit;
}
while(!empty($farr)){
$_sub = array_splice($farr, 0, 10000); //每次取出$farr中1000个
for($i=0,$scount=count($_sub);$i<$scount;$i++){
$arr = explode($spt,$_sub[$i]);
$Uarr[] = $arr[1]; //vurl
$Marr[] = $arr[2]; //vmark
$IParr[] = $arr[3].” |$nbsp;”.$arr[1]; //IP
}
unset($_sub);//用完及时销毁
}
unset($farr);
这里,不难看出,一方面,我们要增加PHP可用内存大小,另一方面,只要我们想办法对数组进行分批处理,分而治之,将用过的变量及时销毁(unset),一般是不会出现溢出问题的。
另外,为了节省PHP程序内存损耗,我们应当尽可能减少静态变量的使用,在需要数据重用时,可以考虑使用引用(&)。再一点就是:数据库操作完成后,要马上关闭连接;一个对象使用完,要及时调用析构函数(__destruct())。
============================unset销毁变量并释放内存问题
PHP的unset()函数用来清除、销毁变量,不用的变量,我们可以用unset()将它销毁。但是某些时候,用unset()却无法达到销毁变 量占用的内存!我们先看一个例子:
<?php
$s=str_repeat('1',255); //产生由255个1组成的字符串
$m=memory_get_usage(); //获取当前占用内存
unset($s);
$mm=memory_get_usage(); //unset()后再查看当前占用内存
echo $m-$mm;
?>
最后输出unset()之前占用内存减去unset()之后占用内存,如果是正数,那么说明unset($s)已经将$s从内存中销毁(或者说,unset()之后内存占用减少了),可是我在PHP5和windows平台下,得到的结果是:0。这是否可以说明,unset($s)并没有起 到销毁变量$s所占用内存的作用呢?我们再作下面的例子:
<?php
$s=str_repeat('1',256); //产生由256个1组成的字符串
$m=memory_get_usage(); //获取当前占用内存
unset($s);
$mm=memory_get_usage(); //unset()后再查看当前占用内存
echo $m-$mm;
?>
这个例子,和上面的例子几乎相同,唯一的不同是,$s由256个1组成,即比第一个例子多了一个1,得到结果是:272。这是否可以说 明,unset($s)已经将$s所占用的内存销毁了?
通过上面两个例子,我们可以得出以下结论:
结论一、unset()函数只能在变量值占用内存空间超过256字节时才会释放内存空间。
那么是不是只要变量值超过256,使用unset就可以释放内存空间呢?我们再通过一个例子来测试一下:
<?php
$s=str_repeat('1',256); //这和第二个例子完全相同
$p=&$s;
$m=memory_get_usage();
unset($s); //销毁$s
$mm=memory_get_usage();
echo $p.'<br />';
echo $m-$mm;
?>
刷新页面,我们看到第一行有256个1,第二行是0,按理说我们已经销毁了$s,而$p只是引用$s的变量,应该是没有内容了,另 外,unset($s)前后内存占用没变化!现在我们再做以下的例子:
<?php
$s=str_repeat('1',256); //这和第二个例子完全相同
$p=&$s;
$m=memory_get_usage();
$s=null; //设置$s为null
$mm=memory_get_usage();
echo $p.'<br />';
echo $m-$mm;
?>
现在刷新页面,我们看到,输出$p已经是没有内容了,unset()前后内存占用量之差是272,即已经清除了变量占用的内存。本例中的$s=null也 可以换成unset(),如下:
<?php
$s=str_repeat('1',256); //这和第二个例子完全相同
$p=&$s;
$m=memory_get_usage();
unset($s); //销毁$s
unset($p);
$mm=memory_get_usage();
echo $p.'<br />';
echo $m-$mm;
?>
我们将$s和$p都使用unset()销毁,这时再看内存占用量之差也是272,说明这样也可以释放内存。那么,我们可以得到另外一条结论:
结论二、只有当指向该变量的所有变量(如引用变量)都被销毁后,才会释放内存。
相关文章:
PHP内存溢出Allowed memory size of 解决办法
以前追踪过这个问题,但是那个时候工具用的不太好,没看的这么细,这次搞的比较细,修正了偶以前的看法 .于是写小文一篇总结一下. PHP偶尔会爆一下如下 错误Allowed memory size of xxx bytes exhausted at xxx:xxx (tried to allocate xxx bytes) 不想看原理的,直接跳到最后…...
重回代码,学习总结
回顾加总结 2021年 自动化测试 1.ETL 数据库开发维护(oracle pl/sql) 2.自动化测试(javaseleniumcucumber) 2022年 功能测试 1.功能测试(学习测试用例,postman测试) 2.性能测试(jmeter初学) 2023年 测试开发 1.学习了…...
【Leetcode -86.分隔链表 -92.反转链表Ⅱ】
Leetcode Leetcode -86.分隔链表Leetcode -92.反转链表Ⅱ Leetcode -86.分隔链表 题目:给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你应当 保留 两个分区中每…...
算法记录 | 48 动态规划
198.打家劫舍 思路: 1.确定dp数组(dp table)以及下标的含义:dp[i]:前 i 间房屋所能偷窃到的最高金额。 2.确定递推公式:dp[i] max(dp[i - 2] nums[i-1], dp[i - 1]) i间房屋的最后一个房子是nums[i−…...
CRM部署Always on 后 CRM报无法更新数据库,数据库只读,且读写分离不正常
CRM部署Always on 后 CRM报无法更新数据库,数据库只读,读写分离不正常 问题描述背景信息问题原因解决方案 问题描述 CRM部署Always on 后 CRM报无法更新数据库,数据库只读 读写分离不正常,出现错乱链接。 背景信息 1.2个节点配置SQL serve…...
麓言信息设计创意思维,打开设计师思路
在现在快速发展的时代,信息纷杂繁琐,如果一个设计不能让人眼前一亮,印象深刻,只会沦为平凡作品,无亮点无用处。正所谓,无设计不创意,这句口号正是喊出对设计的要求。 伴随着时代的发展、…...
POJ3704 括号匹配问题 递归方法
目录 题目 算法 完整代码 题目 参考 递归: https://blog.csdn.net/qq_45272251/article/details/103257953 利用了递归, 但思路稍复杂了 循环: https://blog.csdn.net/weixin_50340097/article/details/114579805 (看起来是递归其实是循环. 每次递归其实是循环内一次迭…...
leetcode — JavaScript专题(三):完全相等的 JSON 字符串、复合函数、 分组、柯里化、将对象转换为 JSON 字符串
专栏声明:只求用最简单的,容易理解的方法通过,不求优化,不喜勿喷 2628. 完全相等的 JSON 字符串 题面 给定两个对象 o1 和 o2 ,请你检查它们是否 完全相等 。 对于两个 完全相等 的对象,它们必须包含相…...
OGNL 的表达式
目录 概念 基本原理 基本语法 1、访问Root区域对象基本语法 2、访问Context区域对象基本语法 符号含义 概念 Object-Graph Navigation Language 对象-图形导航语言, 主要用于访问对象的数据和方法。 基本原理 主要由3部分构成:1.OGNL引擎 …...
JAVA面试中遇到的那些坑,80%的人都种过招
面试,是很多学完Java开发的人不得不面对的问题。小编经常听到学员抱怨,明明觉得自己学的不错,为什么到了面试的时候就凉凉了?为什么有的面试官会一直问业务层面的问题,让人措手不及? 其实,我们在学习Java知识的同时…...
【测试开发】单元测试、基准测试和性能分析(以 Go testing 为例)
一、为什么需要测试🤔️ 你写不出 bug-free 的代码。你认为自己写出了 bug-free 的代码,但它在你意想不到的地方出错了。你觉得自己写出了永不出错的代码,但它的性能十分糟糕。 二、在开发过程中做好测试(理想情况下)…...
linux中一条命令查询当前端口的进程,然后拿到进程pid,作为另一条杀死进程的参数
1. 可以使用lsof命令来查询端口对应的进程,然后使用awk命令提取PID,最后将其作为另一条命令的参数。 例如,如果要查询端口为8080的进程: lsof -i :8080 | awk NR2{print $2}其中,-i选项指定查询网络连接,…...
程序员找工作难吗?我用亲身经历来告诉大家
我看到很多同学说今年的程序员找工作难。我的心里也有一定预期,但直到我出来之后才真正地感受到这股寒冬有多么凛冽。 一个外包公司有四五个招聘人员,然后外包公司有十来个,一个公司的岗位会分发给这些各个不同的外包公司。所以你看到我沟通…...
【Web服务】HTTP和DNS重要知识
304状态码 HTTP状态码中的304状态码表示"未修改",通常在客户端发起了一个带有If-Modified-Since头部的GET请求时会得到这个响应。服务器通过比较If-Modified-Since头部指定的时间戳和资源的最后修改时间来判断资源是否被修改过,如果没有修改则…...
【C++】-关于类和对象的默认成员函数(中)-拷贝构造函数和赋值运算符重载函数
💖作者:小树苗渴望变成参天大树 ❤️🩹作者宣言:认真写好每一篇博客 💨作者gitee:gitee 💞作者专栏:C语言,数据结构初阶,Linux,C 如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点…...
c++11上篇
c11 1.C11简介2.列表初始化2.1 {}初始化2.2 std::initializer_list 3.变量类型推导3.1 auto3.2 decltype3.3 nullptr 4.范围for循环5.final与override6.智能指针7.新增加容器---静态数组array、forward_list以及unordered系列8.默认成员函数控制9.右值引…...
异构无线传感器网络路由算法研究(Matlab代码实现)
目录 💥1 概述 📚2 运行结果 🎉3 参考文献 👨💻4 Matlab代码 💥1 概述 无线传感器网络(Wireless Sensor Networks, WSN)是一种新型的融合传感器、计算机、通信等多学科的信息获取和处理技术的网络,…...
MySQL数据库——MySQL TRUNCATE:清空表记录
MySQL 提供了 DELETE 和 TRUNCATE 关键字来删除表中的数据。下面主要讲解一下 TRUNCATE 关键字的使用。 TRUNCATE 关键字用于完全清空一个表。其语法格式如下: TRUNCATE [TABLE] 表名 其中,TABLE 关键字可省略。 例 1 新建表 tb_student_course&…...
财报解读:连续三年逆势增长的背后,欧派家居到底靠的是什么?
能在过去3年逆势增长的家居企业并不多,而欧派家居就是其中一个。4月25日,欧派家居发布2022年年度报告。据年报数据显示,2022年,欧派家居共实现营业收入224.80亿元,净利润约26.88亿元。 从2020年到2022年,欧…...
希望计算机专业同学都知道这些宝藏博主
湖科大教书匠——计算机网络 “宝藏老师”、“干货满满”、“羡慕湖科大”…这些都是网友对这门网课的评价,可见网课质量之高! 湖南科技大学《计算机网络》微课堂是该校高军老师精心制作的视频课程,用简单的语言描述复杂的问题,…...
1694_week1_MIT使用Python编程学习手记1
全部学习汇总: GreyZhang/python_basic: My learning notes about python. (github.com) 首先说明一下,这部分信息的整理只是我个人的理解。由于自己的知识功底以及英语水准,很可能会有大量的疏漏。再此,我只想把自己学习时候的一…...
第二十一章 光源
光源是每个场景必不可少的部分,光源除了能够照亮场景之外,还可以产生阴影效果。 Unity中分为四种光源类型: 1. 方向光:Directional Light 用于模拟太阳光,方向光任何地方都能照射到。 2. 点光源:Point L…...
CVPR 2023 超分辨率(super-resolution)方向上接收论文总结
目录 CVPR 2023图像超分任意尺度超分盲超分 视频超分特殊场景 总结参考资料 CVPR 2023 官网链接:https://cvpr2023.thecvf.com/ 会议时间:2023年6月18日-6月22日,加拿大温哥华 CVPR 2023统计数据: 提交:9155篇论文接…...
Python 基于 Django 的学生成绩管理系统,可视化界面(附源码,教程)
1简介 对于学生成绩管理系统,充分运用现代化的信息技术手段,对于学生成绩信息管理发展的趋势就是信息化,信息化时代下的信息管理,需要深化信息管理体制与手段的改革,充分运用信息化手段来全方位的进行学生成绩管理系统…...
第二弹进阶吴恩达 ChatGPT Prompt 技巧
第一弹笔记在这里: 总结吴恩达 ChatGPT Prompt 免费课程 今天分享第二弹,进阶篇。 第一点,任务序列化。 通常看完一篇长文,脑子里往往充满无数疑问。急切想知道所有答案,必须列一个问题清单。对话式问法,对…...
约瑟夫环问题
约瑟夫问题 题目描述 n n n 个人围成一圈,从第一个人开始报数,数到 m m m 的人出列,再由下一个人重新从 1 1 1 开始报数,数到 m m m 的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。…...
JavaScript中的异步编程
当我们在编写JavaScript代码时,经常会遇到需要执行长时间运行的任务的情况,例如从服务器获取数据或进行复杂的计算。在这些情况下,我们不希望阻塞用户界面,因为这会使网站看起来卡顿,甚至无响应。为了避免这种情况&…...
奥斯汀独家对话|从机构的「拉扯」中成长的美国加密监管
前言 4月25日,在美国得克萨斯州的首府奥斯汀,这座充满活力和创造力的城市,欧科云链研究院与来自哥伦比亚商学院的Austin Campbell教授就美国加密监管以及其相关话题进行了一次深入探讨。双方讨论了美国整体的监管问题、监管逻辑、最新的稳…...
PostgreSQL16中pg_dump的LZ4和ZSTD压缩
PostgreSQL16中pg_dump的LZ4和ZSTD压缩 pg_dump压缩lz4和zstd LZ4和ZSTD压缩算法合入了PG16。LZ4补丁的作者是Georgios Kokolatos。由Tomas Vondra提交。由Michael Paquier、Rachel Heaton、Justin Pryzby、Shi Yu 和 Tomas Vondra 审阅。提交消息是: Expand pg_dum…...
网络安全基础入门学习路线
在大多数的思维里总觉得学习网络安全得先收集资料、学习编程、学习计算机基础,这样不是不可以,但是这样学效率太低了! 你要知道网络安全是一门技术,任何技术的学习一定是以实践为主的。也就是说很多的理论知识其实是可以在实践中…...
永州高端网站建设/酒店seo是什么意思
1、作用 权重分析是通过熵权法对问卷调查的指标的重要性进行权重输出,根据信息熵的定义,对于某项指标,可以用熵值来判断某个指标的离散程度,其信息熵值越小,指标的离散程度越大, 该指标对综合评价的影响&a…...
电气工程专业毕业设计代做网站/小红书seo软件
px像素(Pixel)。相对长度单位。像素px是相对于显示器屏幕分辨率而言的。 em是相对长度单位。相对于当前对象内文本的字体尺寸,多理解父级设定font-size的尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。 任意…...
厦门外贸网站建设哪家公司大/app推广一手单
主要内容1.编码问题2.File类的使用3.RandomAccessFile的使用4.I/O 输入输出流编码问题:1 importjava.io.UnsupportedEncodingException;23 public class编码问题 {4 public static voidmain(String[] args) {5 //我们项目的默认编码是GBK6 String s "测试 ABC…...
wordpress 360加速/抖音seo培训
为了将print函数输出的内容对齐,笔者在http://www.jb51.net/article/55768.htm中找到了左右对齐的方法。整理如下: 一、数值类型(int、float) # %d、%f是占位符 >>> a 3.1415926 >>> print("%d"%a) …...
wordpress主题 设定/自己如何优化网站排名
在新建类的时候,是可以直接表面你要新建的这个类是干啥的,即,给这个新建的类加上注释。我这详细记录示范下,在idea里面是怎么设置和操作的。1.idea创建类的时候,自动给类加注释的设置示范。这地方,可以设置…...
什么网站有做册子版/学生没钱怎么开网店
创业公司怎样才能被大公司收购?对于一家创业公司来说,虽然自己坚持下去也是个不错的选择,不过要是被像苹果或Google这样最具价值的公司收购,那将是一件无比激动人心的事,那怎么做才能受到它们的青睐,吸引它…...