PHP内存溢出优化代码详解


Posted in PHP onFebruary 26, 2021

相信很多人做大批量数据导出和数据导入的时候,经常会遇到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引擎提供为了处理请求相关数据提供了一种特殊的内存管理器。请求相关数据是只需要服务单个请求,最迟会在请求结束时释放数据。

PHP内存溢出优化代码详解

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

垃圾回收机制

简单说下:

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

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

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

<?php

namespace api\service;

class ExportService
{

 public static $outPutFile = '';

 /**
 * 导出文件
 * @param string $fileName
 * @param $data
 * @param array $formFields
 * @return mixed
 */
 public static function exportData($fileName = '', $data, $formFields = [])
 {
 $fileArr = [];
 $tmpPath = \Yii::$app->params['excelSavePath'];

 foreach (array_chunk($data, 10000) as $key => $value) {
  self::$outPutFile = '';
  $subject  = !empty($fileName) ? $fileName : 'data_';
  $subject  .= date('YmdHis');
  if (empty($value) || empty($formFields)) {
  continue;
  }

  self::$outPutFile = $tmpPath . $subject . $key . '.csv';
  if (!file_exists(self::$outPutFile)) {
  touch(self::$outPutFile);
  }
  $index = array_keys($formFields);
  $header = array_values($formFields);
  self::outPut($header);

  foreach ($value as $k => $v) {
  $tmpData = [];
  foreach ($index as $item) {
   $tmpData[] = isset($v[$item]) ? $v[$item] : '';
  }
  self::outPut($tmpData);
  }
  $fileArr[] = self::$outPutFile;
 }
 
 $zipFile = $tmpPath . $fileName . date('YmdHi') . '.zip';
 $zipRes = self::zipFile($fileArr, $zipFile);
 return $zipRes;
 }

 /**
 * 向文件写入数据
 * @param array $data
 */
 public static function outPut($data = [])
 {
 if (is_array($data) && !empty($data)) {
  $data = implode(',', $data);
  file_put_contents(self::$outPutFile, iconv("UTF-8", "GB2312//IGNORE", $data) . PHP_EOL, FILE_APPEND);
 }
 }

 /**
 * 压缩文件
 * @param $sourceFile
 * @param $distFile
 * @return mixed
 */
 public static function zipFile($sourceFile, $distFile)
 {
 $zip = new \ZipArchive();
 if ($zip->open($distFile, \ZipArchive::CREATE) !== true) {
  return $sourceFile;
 }

 $zip->open($distFile, \ZipArchive::CREATE);
 foreach ($sourceFile as $file) {
  $fileContent = file_get_contents($file);
  $file = iconv('utf-8', 'GBK', basename($file));
  $zip->addFromString($file, $fileContent);
 }
 $zip->close();
 return $distFile;
 }
 
 /**
 * 下载文件
 * @param $filePath
 * @param $fileName
 */
 public static function download($filePath, $fileName)
 {
 if (!file_exists($filePath . $fileName)) {
  header('HTTP/1.1 404 NOT FOUND');
 } else {
  //以只读和二进制模式打开文件
  $file = fopen($filePath . $fileName, "rb");

  //告诉浏览器这是一个文件流格式的文件
  Header("Content-type: application/octet-stream");
  //请求范围的度量单位
  Header("Accept-Ranges: bytes");
  //Content-Length是指定包含于请求或响应中数据的字节长度
  Header("Accept-Length: " . filesize($filePath . $fileName));
  //用来告诉浏览器,文件是可以当做附件被下载,下载后的文件名称为$file_name该变量的值
  Header("Content-Disposition: attachment; filename=" . $fileName);

  //读取文件内容并直接输出到浏览器
  echo fread($file, filesize($filePath . $fileName));
  fclose($file);
  exit();
 }
 }
}

调用处代码

$fileName = "库存导入模板";
$stockRes = []; // 导出的数据
$formFields = [
 'store_id' => '门店ID',
 'storeName' => '门店名称',
 'sku' => 'SKU编码',
 'name' => 'SKU名称',
 'stock' => '库存',
 'reason' => '原因'
];
$fileRes = ExportService::exportData($fileName, $stockRes, $formFields);
$tmpPath = \Yii::$app->params['excelSavePath']; // 文件路径
$fileName = str_replace($tmpPath, '', $fileRes);

// 下载文件
ExportService::download($tmpPath, $fileName);

到此这篇关于PHP内存溢出优化代码详解的文章就介绍到这了,更多相关PHP内存溢出优化内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

PHP 相关文章推荐
PHP编程与应用
Oct 09 PHP
php和js交互一例-PHP教程,PHP应用
Jan 03 PHP
php 应用程序安全防范技术研究
Sep 25 PHP
php 生成饼图 三维饼图
Sep 28 PHP
php 数组动态添加实现代码(最土团购系统的价格排序)
Dec 30 PHP
PHP中__get()和__set()的用法实例详解
Jun 04 PHP
输入值/表单提交参数过滤有效防止sql注入的方法
Dec 25 PHP
PHP中的常见魔术方法功能作用及用法实例
Jul 01 PHP
PHP CURL或file_get_contents获取网页标题的代码及两者效率的稳定性问题
Nov 30 PHP
PHP生成短网址方法汇总
Jul 12 PHP
PHP单例模式详解及实例代码
Dec 21 PHP
Thinkphp结合AJAX长轮询实现PC与APP推送详解
Jul 31 PHP
php自动加载代码实例详解
Feb 26 #PHP
PHP的重载使用魔术方法代码实例详解
Feb 26 #PHP
PHP解密支付宝小程序的加密数据、手机号的示例代码
Feb 26 #PHP
php中get_object_vars()在数组的实例用法
Feb 22 #PHP
MacOS下PHP7.1升级到PHP7.4.15的方法
Feb 22 #PHP
关于PhpStorm设置点击编辑文件自动定位源文件的实现方式
Dec 30 #PHP
Thinkphp5+Redis实现商品秒杀代码实例讲解
Dec 29 #PHP
You might like
php 数组的指针操作实现代码
2011/02/08 PHP
PHP 透明水印生成代码
2012/08/27 PHP
php中foreach结合curl实现多线程的方法分析
2016/09/22 PHP
jQuery插件bgStretcher.js实现全屏背景特效
2015/06/05 Javascript
JavaScript中的cacheStorage使用详解
2015/07/29 Javascript
JS+CSS实现的经典圆角下拉菜单效果代码
2015/10/21 Javascript
Bootstrap Metronic完全响应式管理模板之菜单栏学习笔记
2016/07/08 Javascript
JavaScrpt中如何使用 cookie 设置查看与删除功能
2017/07/09 Javascript
Vue.js项目模板搭建图文教程
2017/09/20 Javascript
vue解决使用webpack打包后keep-alive不生效的方法
2018/09/01 Javascript
Element-ui自定义table表头、修改列标题样式、添加tooltip、:render-header使用
2019/04/11 Javascript
js如何验证密码强度
2020/03/18 Javascript
vue3.0搭配.net core实现文件上传组件
2020/10/29 Javascript
[02:22]2018DOTA2亚洲邀请赛VG赛前采访
2018/04/03 DOTA
[01:36:19]Secret vs NB 2018国际邀请赛小组赛BO2 第一场 8.19
2018/08/21 DOTA
python处理文本文件实现生成指定格式文件的方法
2014/07/31 Python
Python中使用scapy模拟数据包实现arp攻击、dns放大攻击例子
2014/10/23 Python
PHP魔术方法__ISSET、__UNSET使用实例
2014/11/25 Python
python实现斐波那契数列的方法示例
2017/01/12 Python
将pandas.dataframe的数据写入到文件中的方法
2018/12/07 Python
对python中Librosa的mfcc步骤详解
2019/01/09 Python
Django数据库类库MySQLdb使用详解
2019/04/28 Python
pyqt5 实现 下拉菜单 + 打开文件的示例代码
2019/06/20 Python
解决Python3下map函数的显示问题
2019/12/04 Python
python实现局域网内实时通信代码
2019/12/22 Python
浅谈python3打包与拆包在函数的应用详解
2020/05/02 Python
使用Keras实现Tensor的相乘和相加代码
2020/06/18 Python
利用Python发送邮件或发带附件的邮件
2020/11/12 Python
最新版 Windows10上安装Python 3.8.5的步骤详解
2020/11/28 Python
苹果Mac升级:MacSales.com
2017/11/20 全球购物
WWE美国职业摔角官方商店:WWE Shop
2018/11/15 全球购物
节水倡议书范文
2014/04/15 职场文书
集中采购方案
2014/06/10 职场文书
试用期解除劳动合同通知书
2015/04/16 职场文书
关于PHP数组迭代器的使用方法实例
2021/11/17 PHP
PostgreSQL常用字符串分割函数整理汇总
2022/07/07 PostgreSQL