- 浏览: 2539958 次
- 性别:
- 来自: 深圳
文章分类
- 全部博客 (676)
- linux运维 (157)
- php (65)
- mysql (78)
- nginx (27)
- apche (18)
- framework (6)
- windows (9)
- IDE工具 (23)
- struts2 (7)
- java (13)
- 移动互联网 (14)
- memcache redis (23)
- shell基础/命令/语法 (37)
- shell (50)
- puppet (4)
- C (11)
- python (9)
- 产品经理 (27)
- Sphinx (4)
- svn (12)
- 设计构建 (12)
- 项目管理 (44)
- SEO (1)
- 网站架构 (26)
- 审时度势 (42)
- 网络 (14)
- 激发事业[书&视频] (81)
- 其它 (12)
- 摄影 (8)
- android (21)
最新评论
-
zhongmin2012:
原文的书在哪里
数据库水平切分的实现原理解析---分库,分表,主从,集群,负载均衡器 -
renzhengzhi:
你好,请问个问题,从master同步数据到slave的时候,s ...
数据库水平切分的实现原理解析---分库,分表,主从,集群,负载均衡器 -
ibc789:
你好,看了你的文章,我想请教个问题, 我在用 redis的时候 ...
redis 的两种持久化方式及原理 -
iijjll:
写得非常好
数据库水平切分的实现原理解析---分库,分表,主从,集群,负载均衡器 -
iijjll:
写得非常好
数据库水平切分的实现原理解析---分库,分表,主从,集群,负载均衡器
============================Allowed memory size of xxx bytes
以前追踪过这个问题,但是那个时候工具用的不太好,没看的这么细,这次搞的比较细,修正了偶以前的看法
.于是写小文一篇总结一下.
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()。详情可考:
http://bugs.php.net/bug.php?id=33595。
问题症状
如果两个对象之间存在着相互引用的关系,如“父对象-子对象”,对父对象调用 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,说明这样也可以释放内存。那么,我们可以得到另外一条结论:
结论二、只有当指向该变量的所有变量(如引用变量)都被销毁后,才会释放内存。
发表评论
-
wamp 升级php apache mysql
2014-02-18 14:30 1189wamp对于日常开发来说会增添非常大的方便 但是对于集成 ... -
[被震撼到了]我的2009年自我反省【也名10问PHP程序员】php程序员进阶篇
2012-10-29 11:22 10071.首先看了PHP的源码API函数 ,对于许多口水仗的争论一 ... -
五种常见的PHP设计模式
2012-08-15 13:37 1098原文地址:http://www.ibm.com/develop ... -
PHP的Realpath Cache
2012-07-03 09:53 3760PHP的缓存有很多种,包括输出缓冲(ob系列函数),opcod ... -
nginx+php-fmp 内存不释放
2012-06-20 11:01 5234由于服务器只有600M的内 ... -
[转]探究php底层运行机制
2012-04-17 14:36 2096http://www.myext.cn/Article/921 ... -
APC 缓存
2012-04-16 16:22 6113APC主要有两个作用,一是将php的编译缓存保存在共享内存中, ... -
【汇总】PHP-FPM 配置优化
2012-02-25 11:41 17346http://www.linuxidc.com/Linux/2 ... -
【推荐转载】谁贪占了我的系统资源 php-fpm
2012-02-16 14:12 1371测试人员向我们反映:在Facebook平台的游戏比其它平台 ... -
php代码性能分析工具:XHProf
2012-01-30 15:11 4890http://www.ooso.net/archives/52 ... -
神奇的Fastcgi_Finish_Request
2012-01-17 10:52 1252当PHP运行在FastCGI模式时,PHP FPM提供了一个名 ... -
PHP Warning: Xdebug MUST be loaded as a Zend extension in Unknown on line 0 解决办法
2011-11-07 17:18 3394;extension=php_xdebug.dll z ... -
【转】php 程序员
2011-11-05 12:01 948http://www.blags.org/php-pro ... -
cookies之PHPSESSID
2011-10-24 21:52 2952// 设置str function get_cooki ... -
并发同步
2011-10-11 14:26 1452============================= ... -
PHP核心编译配置选项列表
2011-09-15 11:21 1229PHP 的编译配置详细选项 ... -
Hudson_CI:PHP持续集成
2011-09-09 16:29 3098一、持续集成的概念 概念网上很多了,这里就不再详细说了。 ... -
try{}catch{}
2011-07-22 15:13 1218<?php /* 检测(try)、抛出(th ... -
?php消息队列
2011-06-22 09:45 2429php-通过共享内存实现消息队列和进程通信的两个类 h ... -
Http Status Code/http响应状态码
2011-06-01 13:49 1327100 Continue 指示客户端应该继续请求。回送用于通 ...
相关推荐
PHP 中最常见的错误之一是 "Allowed memory size of 134217728 bytes exhausted",這個錯誤是指 PHP腳本在執行過程中,超出了允許的内存限制,導致腳本無法繼續執行。在這篇文章中,我們將詳細解釋這個錯誤的原因、...
通过以上这些策略,你可以有效地解决PHP中"Allowed memory size of bytes exhausted"的问题,并优化你的代码以更高效地利用内存资源。记住,优化不仅关乎提高内存限制,更重要的是编写更聪明的代码,减少不必要的...
如果你的ThinkPHP提示你:致命错误(Fatal error: Allowed memory size),根据网上说的提高服务器可使用内存,我觉得都不是好的解决办法。麻烦也没必要。因为这是ThinkPHP本身存在BUG。 错误提示:Fatal error: ...
PHP错误“Allowed memory size of 67108864 bytes exhausted”通常表示程序运行过程中已用尽了分配给它的内存,导致内存溢出。这个错误在处理大数据量、复杂运算或者大型文件时尤其常见。在PHP中,默认的内存限制...
在PHP编程过程中,有时会遇到一个常见的错误提示:“Fatal error: Allowed memory size of [内存大小] bytes exhausted”,这意味着PHP在执行脚本时超过了分配给它的内存限制。这通常是由于程序存在内存泄漏、处理...
主要介绍了Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 2611816 bytes)错误的解决方法,需要的朋友可以参考下
根据提供的文件信息,我们将详细探讨在安装悟空CRM时遇到的“Fatal error: Allowed memory size of 8388608 bytes”错误及其解决办法。该问题通常表示PHP在执行过程中超过了分配的内存限制,导致程序无法继续运行。...
### Spring MVC 重定向导致内存溢出解决方案 在Spring MVC框架中进行页面重定向操作时,可能会遇到因重定向导致的内存溢出问题。本文将详细介绍该问题的原因、原理以及解决方法。 #### 一、问题背景及原因分析 在...
错误提示可能类似于“PHP Fatal error: Allowed memory size of XXX bytes exhausted”。针对这类问题,开发者可以采取多种策略来优化内存使用。 首先,要理解PHP的内存管理机制。PHP脚本默认有内存使用上限,可以...
这种情况通常表现为在处理一定数量的数据后,系统提示内存耗尽,例如“Allowed memory size of 134217728 bytes exhausted”。在描述中提到的现象是在对`edu_ocr_img`表进行归档操作时,每处理几万个数据,就会触发...
在运行PHP程序,通常会遇到“Fatal Error: Allowed memory size of xxxxxx bytes exhausted”的错误, 这个意味着PHP脚本使用了过多的内存,并超出了系统对其设置的允许最大内存
本文将详细介绍在使用curl访问特定域名时遇到405 Method Not Allowed错误的解决方法。首先,我们先来理解什么是405错误以及其背后可能的原因。 HTTP状态码405 Method Not Allowed表示客户端请求的HTTP方法不被...
然而,这种方式在处理大数据量时会消耗大量内存,从而可能导致"Allowed memory size exhausted"的错误。 为了解决这个问题,可以采用非缓冲查询(Unbuffered queries),也称为流式查询(Streaming queries)。非...
Laravel作为流行的PHP web开发框架,通过其灵活的架构和丰富的生态系统,使得开发者能够轻松地与各种数据库系统进行交互,包括Informix。 首先,我们需要了解Laravel的数据库连接和查询构建器。Laravel提供了统一的...
Android WebView 报 Not allowed to load local resource错误的解决办法 博客地址:http://blog.csdn.net/yuzhiqiang_1993/article/details/76228541
Allowed memory size of 8388608 bytes exhausted (tried to allocate 1298358 bytes) 出现该错误的原因:在确保不是程序产生的原因(例如死循环),是由于php页面消耗的最大内存默认是为 8M (在PHP的ini件里可以...