经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » PHP » 查看文章
PHP内存溢出是什么样的
来源:cnblogs  作者:PHP架构师圈子  时间:2021/3/1 9:28:27  对本文有异议

相信很多人做大批量数据导出和数据导入的时候,经常会遇到PHP内存溢出的问题,在解决了问题之后,总结了一些经验,整理成文章记录下。

优化点

  1. 优化SQL语句,避免慢查询,合理的建立索引,查询指定的字段,sql优化这块在此就不展开了。
  2. 查询的结果集为大对象时转数组处理,框架中一般有方法可以转,如Laravel中有toArray(),Yii2中有asArray()。
  3. 对于大数组进行数据切割处理,PHP函数有array_chunk()、array_slice()。
  4. 对于大型的字符串和对象,使用引用传递&。
  5. 用过的变量及时unset。
  6. 导出的文件格式由excel改为csv
  7. ini_set('memory_limit',''),设置程序可以使用的内存(不建议这样做)。

思考

内存管理

PHP的内存什么怎么管理的呢? 在学C语言时,开发者是需要手动管理内存。在PHP中,Zend引擎提供为了处理请求相关数据提供了一种特殊的内存管理器。请求相关数据是只需要服务单个请求,最迟会在请求结束时释放数据。

防止内存泄漏并尽可能快地释放所有内存是内存管理的重要组成部分。因为安全原因,Zend引擎会释放所有上面提到的API锁分配的内存。

垃圾回收机制

简单说下:

PHP5.3之前,采用引用计数的方式管理。PHP中的变量存在zval的变量容器中,变量被引用的时,引用计数+1,变量引用计数为0时,PHP将在内存中销毁这个变量。但是在引用计数循环引用时,引用计数就不会消减为0,导致内存泄漏。

PHP5.3之后做了优化,并不是每次引用计数减少都进入回收周期,只有根缓冲区满额后才开始进行垃圾回收,这样可以解决循环引用的问题,也可以将总内存泄漏保持在一个阈值之下。

代码

由于使用phpexcel时经常会遇到内存溢出,下面分享一段生成csv文件的代码:

  1. <?php
  2. namespace api\service;
  3. class ExportService
  4. {
  5. public static $outPutFile = '';
  6. /**
  7. * 导出文件
  8. * @param string $fileName
  9. * @param $data
  10. * @param array $formFields
  11. * @return mixed
  12. */
  13. public static function exportData($fileName = '', $data, $formFields = [])
  14. {
  15. $fileArr = [];
  16. $tmpPath = \Yii::$app->params['excelSavePath'];
  17. foreach (array_chunk($data, 10000) as $key => $value) {
  18. self::$outPutFile = '';
  19. $subject = !empty($fileName) ? $fileName : 'data_';
  20. $subject .= date('YmdHis');
  21. if (empty($value) || empty($formFields)) {
  22. continue;
  23. }
  24. self::$outPutFile = $tmpPath . $subject . $key . '.csv';
  25. if (!file_exists(self::$outPutFile)) {
  26. touch(self::$outPutFile);
  27. }
  28. $index = array_keys($formFields);
  29. $header = array_values($formFields);
  30. self::outPut($header);
  31. foreach ($value as $k => $v) {
  32. $tmpData = [];
  33. foreach ($index as $item) {
  34. $tmpData[] = isset($v[$item]) ? $v[$item] : '';
  35. }
  36. self::outPut($tmpData);
  37. }
  38. $fileArr[] = self::$outPutFile;
  39. }
  40. $zipFile = $tmpPath . $fileName . date('YmdHi') . '.zip';
  41. $zipRes = self::zipFile($fileArr, $zipFile);
  42. return $zipRes;
  43. }
  44. /**
  45. * 向文件写入数据
  46. * @param array $data
  47. */
  48. public static function outPut($data = [])
  49. {
  50. if (is_array($data) && !empty($data)) {
  51. $data = implode(',', $data);
  52. file_put_contents(self::$outPutFile, iconv("UTF-8", "GB2312//IGNORE", $data) . PHP_EOL, FILE_APPEND);
  53. }
  54. }
  55. /**
  56. * 压缩文件
  57. * @param $sourceFile
  58. * @param $distFile
  59. * @return mixed
  60. */
  61. public static function zipFile($sourceFile, $distFile)
  62. {
  63. $zip = new \ZipArchive();
  64. if ($zip->open($distFile, \ZipArchive::CREATE) !== true) {
  65. return $sourceFile;
  66. }
  67. $zip->open($distFile, \ZipArchive::CREATE);
  68. foreach ($sourceFile as $file) {
  69. $fileContent = file_get_contents($file);
  70. $file = iconv('utf-8', 'GBK', basename($file));
  71. $zip->addFromString($file, $fileContent);
  72. }
  73. $zip->close();
  74. return $distFile;
  75. }
  76. /**
  77. * 下载文件
  78. * @param $filePath
  79. * @param $fileName
  80. */
  81. public static function download($filePath, $fileName)
  82. {
  83. if (!file_exists($filePath . $fileName)) {
  84. header('HTTP/1.1 404 NOT FOUND');
  85. } else {
  86. //以只读和二进制模式打开文件
  87. $file = fopen($filePath . $fileName, "rb");
  88. //告诉浏览器这是一个文件流格式的文件
  89. Header("Content-type: application/octet-stream");
  90. //请求范围的度量单位
  91. Header("Accept-Ranges: bytes");
  92. //Content-Length是指定包含于请求或响应中数据的字节长度
  93. Header("Accept-Length: " . filesize($filePath . $fileName));
  94. //用来告诉浏览器,文件是可以当做附件被下载,下载后的文件名称为$file_name该变量的值
  95. Header("Content-Disposition: attachment; filename=" . $fileName);
  96. //读取文件内容并直接输出到浏览器
  97. echo fread($file, filesize($filePath . $fileName));
  98. fclose($file);
  99. exit();
  100. }
  101. }
  102. }

调用处代码

  1. $fileName = "库存导入模板";
  2. $stockRes = []; // 导出的数据
  3. $formFields = [
  4. 'store_id' => '门店ID',
  5. 'storeName' => '门店名称',
  6. 'sku' => 'SKU编码',
  7. 'name' => 'SKU名称',
  8. 'stock' => '库存',
  9. 'reason' => '原因'
  10. ];
  11. $fileRes = ExportService::exportData($fileName, $stockRes, $formFields);
  12. $tmpPath = \Yii::$app->params['excelSavePath']; // 文件路径
  13. $fileName = str_replace($tmpPath, '', $fileRes);
  14. // 下载文件
  15. ExportService::download($tmpPath, $fileName);

以上内容希望帮助到大家,更多PHP大厂PDF面试文档,PHP进阶架构视频资料,PHP精彩好文免费获取可以微信搜索关注公众号:PHP开源社区,或者访问:

2021金三银四大厂面试真题集锦,必看!

四年精华PHP技术文章整理合集——PHP框架篇

四年精华PHP技术文合集——微服务架构篇

四年精华PHP技术文合集——分布式架构篇

四年精华PHP技术文合集——高并发场景篇

四年精华PHP技术文章整理合集——数据库篇

原文链接:http://www.cnblogs.com/uuuuu55/p/14440021.html

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

本站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号