谈谈关于PHP内存溢出的思考
发布:smiling 来源: PHP粉丝网 添加日期:2022-06-06 08:29:32 浏览: 评论:0
最近做大批量数据导出和数据导入的时候,经常会遇到PHP内存溢出的问题,在解决了问题之后,总结了一些经验,整理成文章记录下。
优化点
优化SQL语句,避免慢查询,合理的建立索引,查询指定的字段,sql优化这块在此就不展开了。
查询的结果集为大对象时转数组处理,框架中一般有方法可以转,如Laravel中有toArray(),Yii2中有asArray()。
对于大数组进行数据切割处理,PHP函数有array_chunk()、array_slice()。
对于大型的字符串和对象,使用引用传递&。
用过的变量及时unset。
导出的文件格式由excel改为csv
ini_set(‘memory_limit’,’’),设置程序可以使用的内存(不建议这样做)。
思考
内存管理
PHP的内存什么怎么管理的呢? 在学C语言时,开发者是需要手动管理内存。在PHP中,Zend引擎提供为了处理请求相关数据提供了一种特殊的内存管理器。请求相关数据是只需要服务单个请求,最迟会在请求结束时释放数据。
1.png
上图是来自于官网的描述截图
防止内存泄漏并尽可能快地释放所有内存是内存管理的重要组成部分。因为安全原因,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 = !emptyempty($fileName) ? $fileName : 'data_';
- $subject .= date('YmdHis');
- if (emptyempty($value) || emptyempty($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) && !emptyempty($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);
Tags: PHP内存溢出
- 上一篇:使用phpdbg来调试php程序的方法介绍
- 下一篇:最后一页
相关文章
- ·PHP对象相互引用的内存溢出实例分析(2021-04-10)
- ·PHP内存溢出优化代码详解(2022-04-13)
推荐文章
热门文章
最新评论文章
- 写给考虑创业的年轻程序员(10)
- PHP新手上路(一)(7)
- 惹恼程序员的十件事(5)
- PHP邮件发送例子,已测试成功(5)
- 致初学者:PHP比ASP优秀的七个理由(4)
- PHP会被淘汰吗?(4)
- PHP新手上路(四)(4)
- 如何去学习PHP?(2)
- 简单入门级php分页代码(2)
- php中邮箱email 电话等格式的验证(2)