关于Yii2框架跑脚本时内存泄漏问题的分析与解决
发布:smiling 来源: PHP粉丝网 添加日期:2022-01-24 15:06:28 浏览: 评论:0
这篇文章主要给大家介绍了关于Yii2框架跑脚本时内存泄漏问题的分析与解决方法,文中通过示例代码介绍的非常详细,对大家学习或者使用Yii2具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧。
现象
在跑 edu_ocr_img 表的归档时,每跑几万个数据,都会报一次内存耗尽
PHP Fatal error: Allowed memory size of 134217728 bytesexhausted (tried toallocate 135168 bytes)
跟踪代码发现,是在插入时以下代码造成的:
EduOCRTaskBackup::getDb()->createCommand()->batchInsert(EduOCRTaskBackup::tableName(), $fields, $data)->execute();
execute 之后会造成使用内存涨上去,并且在之后 unset 所有变量内存也会有一部分不会删除,直到内存耗尽。
于是跟踪到 Yii2中execute的具体代码块发现在记录 log 的时候会将使用很高的内存,分析代码之后得出造成泄漏的代码块如下:
造成泄漏的代码块
- /**
- * Logs a message with the given type and category.
- * If [[traceLevel]] is greater than 0, additional call stack information about
- * the application code will be logged as well.
- * @param string|array $message the message to be logged. This can be a simple string or a more
- * complex data structure that will be handled by a [[Target|log target]].
- * @param integer $level the level of the message. This must be one of the following:
- * `Logger::LEVEL_ERROR`, `Logger::LEVEL_WARNING`, `Logger::LEVEL_INFO`, `Logger::LEVEL_TRACE`,
- * `Logger::LEVEL_PROFILE_BEGIN`, `Logger::LEVEL_PROFILE_END`.
- * @param string $category the category of the message.
- */
- public function log($message, $level, $category = 'application')
- {
- $time = microtime(true);
- $traces = [];
- if ($this->traceLevel > 0) {
- $count = 0;
- $ts = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
- array_pop($ts); // remove the last trace since it would be the entry script, not very useful
- foreach ($ts as $trace) {
- if (isset($trace['file'], $trace['line']) && strpos($trace['file'], YII2_PATH) !== 0) {
- unset($trace['object'], $trace['args']);
- $traces[] = $trace;
- if (++$count >= $this->traceLevel) {
- break;
- }
- }
- }
- }
- // 这里是造成内存的罪魁祸首
- $this->messages[] = [$message, $level, $category, $time, $traces];
- if ($this->flushInterval > 0 && count($this->messages) >= $this->flushInterval) {
- $this->flush();
- }
- }
造成内存泄漏的原因分析
在 Yii2框架中的 vendor/yiisoft/yii2/log/Logger.php:156 log函数的156行之后会判断 count($this->messages) >= $this->flushInterval
即:内存中存储的 message 的条数要大于等于预设的 $this->flushInterval 才会将内存中的message 刷到磁盘上去。
如果在刷新到磁盘之前就已经将 php.ini 设置的 128M 内存打满的话,会直接报错申请内存耗尽。
很多关于 YII2其他原因的内存泄漏的讨论
https://github.com/yiisoft/yii2/issues/13256
解决方案
在程序开始时,设置 flushInterval 为一个比较小的值
\Yii::getLogger()->flushInterval = 100; // 设置成一个较小的值
在程序执行过程中,每次 execute 之后对内存中的 message 进行 flush
\Yii::getLogger()->flush(true); // 参数传 true 表示每次都会将 message 清理到磁盘中
Tags: Yii2内存泄漏
- 上一篇:Laravel 微信小程序后端实现用户登录的示例代码
- 下一篇:最后一页
推荐文章
热门文章
最新评论文章
- 写给考虑创业的年轻程序员(10)
- PHP新手上路(一)(7)
- 惹恼程序员的十件事(5)
- PHP邮件发送例子,已测试成功(5)
- 致初学者:PHP比ASP优秀的七个理由(4)
- PHP会被淘汰吗?(4)
- PHP新手上路(四)(4)
- 如何去学习PHP?(2)
- 简单入门级php分页代码(2)
- php中邮箱email 电话等格式的验证(2)