经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » PHP » 查看文章
PHP内存溢出的解决方法详解
来源:jb51  时间:2022/7/19 13:03:12  对本文有异议

什么是内存溢出

内存溢出是指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于虚拟机能提供的最大内存。

引起内存溢出的原因有很多种,常见的有以下几种:

1 内存中加载的数据量过于庞大,如一次从数据库取出过多数据;

2 集合类中有对对象的引用,使用完后未清空;

3 代码中存在死循环或循环产生过多重复的对象实体;

4 使用的第三方软件中的BUG;

5 启动参数内存值设定的过小;

下面来看些在开发中经常遇到的内存溢出的实例

内存溢出经常报错的情况

PHP Fatal error: Allowed memory size of 268 435 456 bytes exhausted

1.处理数组时出现内存溢出

1)使用迭代生成器,可以通过继承Iterator接口实现

2)使用关键词yield

  1. function?xrange($start,?$end,?$step?=?1)?{
  2. ????for?($i?=?$start;?$i?<=?$end;?$i?+=?$step)?{
  3. ????????yield?$i;
  4. ????}
  5. }
  6.  
  7. foreach?(xrange(1,?1000000)?as?$num)?{
  8. ????echo?$num,?"\n";
  9. }

2.使用sql查询数据,查出来很多,导致内存溢出

sql语句在mysql中可以查询,但是使用php程序查询就报php内存溢出

1)这个问题在php的官方网站叫缓冲查询和非缓冲查询。php的查询缺省模式是缓冲模式。也就是,查询数据结果一次全部提取到内存里供php程序额外的功能,比如说,计算行数,将指针指向某一行等。

更重要的是程序对数据集反复进行二次查询和过滤操作。但这种缓冲查询模式的缺陷是消耗内存,也就是用空间换速度。

2)另外一种查询模式是非缓冲查询,数据库服务器会一条一条的返回数据,而不是一次全部返回,这样的结果是php程序消耗较少的内存,但却增加了数据库服务器的压力,因为数据库会一直等待php来取数据,一直到数据全部取完。

1.首先查询数据库需要进行limit进行分页查询

2.如果不使用limit,使用非缓冲查询

1.mysql:

  1. $conn?=?mysql_connect("localhost",?"user",?"pass");
  2. $db???=?mysql_select_db("world");
  3. $uresult?=?mysql_unbuffered_query("SELECT?Name?FROM?City");????//非缓冲查询
  4. if?($uresult)?{
  5. ???while?($row?=?mysql_fetch_assoc($uresult))?{
  6. ???????echo?$row['Name']?.?PHP_EOL;
  7. ???}
  8. }

2.pdo_mysql:

  1. $pdo?=?new?PDO("mysql:host=localhost;dbname=world",?'my_user',?'my_pass');
  2. $pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY,?false);????//设置这个属性,就为非缓冲查询
  3. $uresult?=?$pdo->query("SELECT?Name?FROM?City");
  4. if?($uresult)?{
  5. ???while?($row?=?$uresult->fetch(PDO::FETCH_ASSOC))?{
  6. ???????echo?$row['Name']?.?PHP_EOL;
  7. ???}
  8. }

3.mysqli:

  1. $mysqli??=?new?mysqli("localhost",?"user",?"password",?"world");
  2. $uresult?=?$mysqli->query("SELECT?Name?FROM?City",?MYSQLI_USE_RESULT);
  3. if?($uresult)?{
  4. ???while?($row?=?$uresult->fetch_assoc())?{
  5. ???????echo?$row['Name']?.?PHP_EOL;
  6. ???}
  7. }
  8. $uresult->close();

3.假定日志中存放的记录数为500000条,那么解决方案如下

ini_set(‘memory_limit’,’64M’); //重置php可以使用的内存大小为64M,一般在远程主机上是不能修改php.ini文件的,只能通过程序设置。

注:在safe_mode(安全模式)下,ini_set失效

  1. set_time_limit(600);//设置超时限制为6分钟
  2. $farr?=?$Uarr?=?$Marr?=?$IParr?=?$data?=?$_sub?=?array();
  3. $spt?=?”$@#!$”;
  4. $root?=?”/Data/webapps/VisitLog”;
  5. $path?=?$dpath?=?$fpath?=?NULL;
  6. $path?=?$root.”/”.date(“Y-m”,$timestamp);
  7. $dpath?=?$path.”/”.date(“m-d”,$timestamp);
  8.  
  9. for($j=0;$j<24;$j++){
  10. ????$v?=?($j?<?10)???”0″.$j?:?$j;
  11. ????$gpath?=?$dpath.”/”.$v.”.php”;
  12.  
  13. ????if(!file_exists($gpath)){
  14. ????????continue;
  15.  
  16. ????}?else?{
  17. ????????$arr?=?file($gpath);////将文件读入数组中
  18. ????????array_shift($arr);//移出第一个单元-》
  19. ????????$farr?=?array_merge($farr,$arr);
  20. ????????unset($arr);
  21. ????}
  22. }
  23.  
  24. if(empty($this->farr)){
  25. ????echo?”没有相关记录!”;
  26. ????exit;
  27. }
  28.  
  29. while(!empty($farr)){
  30. ????$_sub?=?array_splice($farr,?0,?10000);?//每次取出$farr中1000个
  31. ????for($i=0,$scount=count($_sub);$i<$scount;$i++){
  32. ????????$arr?=?explode($spt,$_sub[$i]);
  33. ????????$Uarr[]?=?$arr[1];?//vurl
  34. ????????$Marr[]?=?$arr[2];?//vmark
  35. ????????$IParr[]?=?$arr[3].”?|$nbsp;”.$arr[1];?//IP
  36. ????}
  37. ????unset($_sub);//用完及时销毁
  38. }
  39. unset($farr);

这里,不难看出,一方面,我们要增加PHP可用内存大小,另一方面,只要我们想办法对数组进行分批处理,分而治之,将用过的变量及时销毁(unset),一般是不会出现溢出问题的。

4.上传excel文件时,出现内存溢出的情况

在文件中分配大点的内存设置内存治标不治本,而且服务器的php.ini(memory_limit =128M)有时候是很难改的。所以在文件中设置。但是只有php.ini中的安全模式safe_mode开启时才可以设置

  1. ini_set('memory_limit',?'521M');

解决方法:

  1. protected?/extensions/ExcelHelper.php?中945行?
  2. $PHPReader->setReadDataOnly(true);??//在拿到数据后进行设置只读
  3.  
  4. ????public?static?function?importFromExcel($filePath,?$blankRowDel?=?false)
  5. ????{
  6. ????????set_time_limit(90);
  7. ????????Yii::import('application.extensions.phpexcel.PHPExcel');
  8. ????????$PHPExcel?=?new?PHPExcel();
  9. ????????//默认用excel2007读取excel,若格式不对,则用之前的版本进行读取
  10. ????????$PHPReader?=?new?PHPExcel_Reader_Excel2007();
  11. ????????if?(!$PHPReader->canRead($filePath))?{
  12. ????????????$PHPReader?=?new?PHPExcel_Reader_Excel5();
  13. ????????????if?(!$PHPReader->canRead($filePath))?{
  14. ????????????????throw?new?Exception('can?not?read?the?excel?file');
  15. ????????????}
  16. ????????}
  17. ????????$PHPReader->setReadDataOnly(true);
  18.  
  19. ????????$PHPExcel??????=?$PHPReader->load($filePath);
  20. ????????$allSheetCount?=?$PHPExcel->getSheetCount();
  21. ????????$excelData?????=?array();
  22. ????????for?($currentSheetNum?=?0;?$currentSheetNum?<?$allSheetCount;?$currentSheetNum++)?{
  23. ????????????//读取excel文件中的第一个工作表
  24. ????????????$currentSheet?=?$PHPExcel->getSheet($currentSheetNum);
  25. ????????????//取得当前表名
  26. ????????????$currentSheetTitle?=?$currentSheet->getTitle();
  27. ????????????//取得最大的列号
  28. ????????????$allColumn?=?$currentSheet->getHighestColumn();
  29. ????????????//取得一共有多少行
  30. ????????????$allRow?=?$currentSheet->getHighestRow();
  31. ????????????//?从第一行获取列名
  32. ????????????$currentRow?=?1;
  33. ????????????//?从第A列开始输出
  34. ????????????$colunmNameArray?=?array();
  35. ????????????$max_column_num??=?PHPExcel_Cell::columnIndexFromString($allColumn);
  36. ????????????for?($current_column_num?=?0;?$current_column_num?<=?$max_column_num;?$current_column_num++)?{
  37. ????????????????$currentColumn?=?PHPExcel_Cell::stringFromColumnIndex($current_column_num);
  38. ????????????????$val???????????=?$currentSheet->getCellByColumnAndRow($current_column_num,?$currentRow)->getValue();
  39. ????????????????if?(empty($val))?{
  40. ????????????????????continue;
  41. ????????????????}
  42. ????????????????if?(is_object($val))?{
  43. ????????????????????$colunmNameArray[$currentColumn]?=?'';
  44. ????????????????????foreach?($val->getRichTextElements()?as?$cell)?{
  45. ????????????????????????$colunmNameArray[$currentColumn]?.=?$cell->getText();
  46. ????????????????????}
  47. ????????????????}?else?{
  48. ????????????????????$colunmNameArray[$currentColumn]?=?$val;
  49. ????????????????}
  50. ????????????}
  51.  
  52. ????????????//从第二行开始输出,因为excel表中第一行为列名
  53. ????????????$sheetData?=?array();
  54. ????????????for?($currentRow?=?2;?$currentRow?<=?$allRow;?$currentRow++)?{
  55. ????????????????//从第A列开始输出?*/
  56. ????????????????$rowData???=?array();
  57. ????????????????$blankCell?=?0;
  58. ????????????????for?($current_column_num?=?0;?$current_column_num?<=?$max_column_num;?$current_column_num++)?{
  59. ????????????????????$currentColumn?=?PHPExcel_Cell::stringFromColumnIndex($current_column_num);
  60. ????????????????????$val???????????=?$currentSheet->getCellByColumnAndRow($current_column_num,?$currentRow)->getValue();
  61. ????????????????????if?(!isset($colunmNameArray[$currentColumn]))?{
  62. ????????????????????????continue;
  63. ????????????????????}
  64. ????????????????????//如果输出汉字有乱码,则需将输出内容用iconv函数进行编码转换,如下将gb2312编码转为utf-8编码输出
  65. ????????????????????if?(is_object($val))?{
  66. ????????????????????????$rowData[$currentColumn]?=?'';
  67. ????????????????????????foreach?($val->getRichTextElements()?as?$cell)?{
  68. ????????????????????????????$rowData[$currentColumn]?.=?$cell->getText();
  69. ????????????????????????}
  70. ????????????????????}?else?{
  71. ????????????????????????$rowData[$currentColumn]?=?$val;
  72. ????????????????????}
  73.  
  74. ????????????????????if?(empty($rowData[$currentColumn]))?{
  75. ????????????????????????$blankCell++;
  76. ????????????????????}
  77. ????????????????}
  78.  
  79. ????????????????if?(!$blankRowDel?||?chr($blankCell?+?64)?!=?$allColumn)?{
  80. ????????????????????$sheetData[]?=?$rowData;
  81. ????????????????}
  82. ????????????}
  83.  
  84. ????????????$excelData[$currentSheetTitle]?=?array(
  85. ????????????????'header'??=>?$colunmNameArray,
  86. ????????????????'content'?=>?$sheetData,
  87. ????????????);
  88. ????????}
  89. ????????return?$excelData;
  90. ????}

到此这篇关于PHP内存溢出的解决方法详解的文章就介绍到这了,更多相关PHP内存溢出内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号