有时候我们在运行php程序的时候会发现 Fatal Error: Out of memory 这样的提示。这有可能是程序中用到了大量的变量和对象,导致分配的内存不够用。
场景
在做数据统计分析时,经常会遇到大数组,可能会发生内存溢出,这里分享一下我的解决方案。还是用例子来说明这个问题,如下:假定日志中存放的记录数为500000条,
那么解决方案如下:
<?php
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 ”没有相关记录!
”;
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的可用内存大小;另一方面,我们需要减少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占用的显存?
从前两个案例中,我们可以得出以下推论:
结论1、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.'
';
echo $m-$mm;
?>刷新页面,我们看到第一行有256个1,第二行有0。 按理说我们已经销毁了$s,而$p只是引用了$s的变量,应该没有任何内容。 另外php 移动文件,unset($s )前后显存使用量没有变化!现在我们做下面的例子
<?php
$s=str_repeat('1',256); //这和第二个例子完全相同
$p=&$s;
$m=memory_get_usage();
$s=null; //设置$s为null
$mm=memory_get_usage();
echo $p.'
';
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.'
';
echo $m-$mm;我们使用 unset() 来销毁 $s 和 $p。 此时显存使用量相差也是272,也就是说显存也可以通过这种方式释放。
那么,通过前面的例子php 移动文件,我们可以得到另一个推论:
结论2.只有当指向该变量的所有变量(如引用变量)都被销毁时,显存才会被释放。
防止内存溢出的一些优化方案
1、尽量减少静态变量的使用,需要数据复用时可以考虑引用(&)。
2、数据库操作完成后,应立即关闭连接;
3、当对象用完时,要及时调用析构函数(__destruct())。
4.使用过的变量及时销毁(unset())
5.可以使用memory_get_usage()函数获取当前占用的显存,并根据当前使用的显存调整程序
6、unset()函数只有当变量值占用显存空间超过256字节时才能释放显存空间。 (由PHP内核的gc垃圾回收机制决定)。
7、只有当指向该变量的所有变量(比如引用变量)都被销毁时,显存才会被释放(PHP变量的底层实现是一个_zval_struct结构体,is_ref__gc表示引用计数 is_ref__gc表示是否是引用)。
第一篇文章:
以上就是本文的全部内容。 希望对你的学习有所帮助。 如果您觉得有用,请支持一下!
常见问题
相关文章
猜你喜欢
- php 单词-初中语文重难数字的搭配. 你需要这些核心短语和经常测试的短语 2024-04-29
- php 时间相加-PHP时区设置 2024-04-28
- php木马查杀-Linux上PHP木马及后门检测总结 2024-04-27
- php注入漏洞-WordPress HDW 播放器插件 'wp-admin/admin 2024-04-27
- 文件管理源码 2024-04-27
- php百分比-PHPMySql比率 2024-04-24
- php查找字符-php 查找一个字符串在另一个字符串中出现的位置 2024-04-24
- php项目开发教程-PHP+MySQL网站开发项目教程教学大纲4.pdf 8页 2024-04-23
- php 进程数-深入探索PHP多进程编程技术 2024-04-23
- php银联支付-银联发布《报告》,金融科技持续渗透支付行业 2024-04-22