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入门学习知识点三 PHP上传
Jul 14 PHP
pdo中使用参数化查询sql
Aug 11 PHP
PHP 获取文件权限函数介绍
Jul 11 PHP
PHP引用符&amp;的用法详细解析
Aug 22 PHP
ThinkPHP实现将本地文件打包成zip下载
Jun 26 PHP
PHP学习笔记(一) 简单了解PHP
Aug 04 PHP
php使用$_POST或$_SESSION[]向js函数传参
Sep 16 PHP
php实现通用的从数据库表读取数据到数组的函数实例
Mar 21 PHP
PHP滚动日志的代码实现
Jun 10 PHP
PHP加密技术的简单实现
Sep 04 PHP
PHP的反射机制实例详解
Mar 29 PHP
thinkphp5框架调用其它控制器方法 实现自定义跳转界面功能示例
Jul 03 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
Windows PHP5和Apache的安装与配置
2009/06/08 PHP
php使用正则表达式进行字符串搜索的方法
2015/03/23 PHP
PHP 使用位运算实现四则运算的代码
2021/03/09 PHP
jquery 插件 web2.0分格的分页脚本,可用于ajax无刷新分页
2008/12/25 Javascript
在UpdatePanel内jquery easyui效果失效的解决方法
2010/04/11 Javascript
jquery 日期分离成年月日的代码
2010/05/14 Javascript
js 去掉空格实例 Trim() LTrim() RTrim()
2014/01/07 Javascript
JQuery实现动态添加删除评论的方法
2015/05/18 Javascript
javascript编写贪吃蛇游戏
2015/07/07 Javascript
jquery编写Tab选项卡滚动导航切换特效
2020/07/17 Javascript
基于javascript实现按圆形排列DIV元素(一)
2016/12/02 Javascript
jQuery实现优雅的弹窗效果(6)
2017/02/08 Javascript
详解Angular 4.x NgIf 的用法
2017/05/22 Javascript
利用jquery如何从json中读取数据追加到html中
2017/12/01 jQuery
angularJS实现动态添加,删除div方法
2018/02/27 Javascript
微信小程序实现banner图轮播效果
2020/06/28 Javascript
vue 解决computed修改data数据的问题
2019/11/06 Javascript
vue router 传参获取不到的解决方式
2019/11/13 Javascript
微信小程序向Java后台传输参数的方法实现
2020/12/10 Javascript
[04:04]DOTA2亚洲邀请赛比赛场馆&酒店全攻略
2017/03/23 DOTA
[03:48]大碗DOTA
2019/07/25 DOTA
python3 实现对图片进行局部切割的方法
2018/12/05 Python
Python多进程fork()函数详解
2019/02/22 Python
python 将有序数组转换为二叉树的方法
2019/03/26 Python
python 实现二维字典的键值合并等函数
2019/12/06 Python
MNIST数据集转化为二维图片的实现示例
2020/01/10 Python
pandas数据选取:df[] df.loc[] df.iloc[] df.ix[] df.at[] df.iat[]
2020/04/24 Python
HTML5之语义标签介绍
2016/07/07 HTML / CSS
美国时装品牌:Nautica(诺帝卡)
2016/08/28 全球购物
Myprotein芬兰官网:欧洲第一运动营养品牌
2019/05/05 全球购物
少年闰土教学反思
2014/02/22 职场文书
小城镇建设汇报材料
2014/08/16 职场文书
年终晚会活动方案
2014/08/21 职场文书
幼儿园教师的自我评价范文
2014/09/17 职场文书
python开发的自动化运维工具ansible详解
2021/08/07 Python
详解MySQL的主键查询为什么这么快
2022/04/03 MySQL