前言

最近项目需要一个常驻内存的脚本来执行队列程序,脚本完成后发现Mysql自动重连部分存在内存溢出,导致运行一段时间后,会超出PHP内存限制退出

排查

发现脚本存在内存溢出后排查了一遍代码,基本确认内存溢出在Mysql查询部分.

如果不确认也可以把不必要的模块去掉,从最基本的业务开始测,如果没有内存泄露,则继续增加模块,基本很快就能定位到内存泄露处的代码

解决

我使用的是PHP7.2,所以mysql查询部分使用了PDO,但是PDO并没有提供关闭连接的方法,只是说将连接connection赋值为Null,PHP便会进行垃圾回收,销毁连接.下面是PHP官方手册中的一段话

连接数据成功后,返回一个 PDO 类的实例给脚本,此连接在 PDO 对象的生存周期中保持活动。要想关闭连接,需要销毁对象以确保所有剩余到它的引用都被删除,可以赋一个 NULL 值给对象变量。如果不明确地这么做,PHP 在脚本结束时会自动关闭连接

然而事情没有这么简单,赋值NULL后PHP并没有将PDO实例回收,依然存在.因为还需要将PDOStatement同样赋值为NULL,否则PHP还是不会去执行垃圾回收.

修改后的代码

namespace app\library;

use \PDO;

class Mysql
{
/** @var string 域名 */
private $host = '127.0.0.1'; /** @var int 端口 */
private $port = 3306; /** @var string 数据库 */
private $dataBase = 'test'; /** @var string 用户名 */
private $userName = 'root'; /** @var string 密码 */
private $password = 'root'; /** @var PDO 数据库连接 */
public $connection; /** @var Mysql 单例 */
private static $instance; /** @var \PDOStatement */
protected $PDOStatement; private function __construct()
{
} /**
* 连接数据库
*/
protected function connection():void
{
$this->connection = new \pdo(
"mysql:host={$this->host}:{$this->port};dbname={$this->dataBase}",
$this->userName,
$this->password,
[PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING]
);
//设置PDO抛出异常
$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} /**
* 获取数据库连接
* @return PDO
*/
private function getConnection(): PDO
{
if ($this->connection instanceof PDO) {
return $this->connection;
} $this->connection(); return $this->connection;
} /**
* 获取实例
* @return Mysql
*/
public static function getInstance()
{
if (is_null(self::$instance)) {
self::$instance = new Mysql();
}
return self::$instance;
} /**
* 重置链接
*/
protected function resetConnection():void
{
$this->connection = null;
//将此赋值操作屏蔽会造成内存溢出
$this->PDOStatement = null;
} /**
* 重连
* @return PDO
*/
protected function reconnection(): PDO
{
$this->resetConnection(); return $this->getConnection();
} /**
* 查询
* @param string $sql sql文本
* @return mixed
*/
public function query(string $sql)
{
try {
$this->PDOStatement = @$this->getConnection()->query($sql);
return $this->PDOStatement->fetch();
} catch (\PDOException $e) {
if (!$this->isMysqlAlive()) {
$this->PDOStatement = $this->reconnection()->query($sql);
return $this->PDOStatement->fetch();
}
throw new $e;
}
} /**
* mysql连接连接是否有效
* @return bool
*/
protected function isMysqlAlive(): bool
{
$errorInfo = $this->connection->errorInfo(); if ($errorInfo[1] != 2006 or $errorInfo[1] != 2013) {
return false;
} return true;
} /**
* 关闭数据库连接
*/
public function close():void
{
$this->connection = null;
$this->PDOStatement = null;
} public function __destruct():void
{
$this->connection = null;
$this->PDOStatement = null;
} /**
* 禁止clone
* @throws \Exception
*/
public function __clone()
{
throw new \Exception('deny clone');
}
}

WIKI

PDO之MySql持久化自动重连导致内存溢出的更多相关文章

  1. php查询mysql返回大量数据结果集导致内存溢出的解决方法

    web开发中如果遇到php查询mysql返回大量数据导致内存溢出.或者内存不够用的情况那就需要看下MySQL C API的关联,那么究竟是什么导致php查询mysql返回大量数据时内存不够用情况? 答 ...

  2. 图片--Android加载图片导致内存溢出(Out of Memory异常)

    Android在加载大背景图或者大量图片时,经常导致内存溢出(Out of Memory  Error),本文根据我处理这些问题的经历及其它开发者的经验,整理解决方案如下(部分代码及文字出处无法考证) ...

  3. 添加IFrame导致内存溢出的解决过程(IE浏览器,目前发现了原因,还未解决)

    1.  现象 每次动态添加iframe时,iexplore.exe进程占据的内存都会增加(大概10M左右),不会自动释放,最终导致内存溢出 2.  解决过程 经过网络的一番搜索,基本上给出的解决方案是 ...

  4. Android加载图片导致内存溢出(Out of Memory异常)

    Android在加载大背景图或者大量图片时,经常导致内存溢出(Out of Memory  Error),本文根据我处理这些问题的经历及其它开发者的经验,整理解决方案如下(部分代码及文字出处无法考证) ...

  5. WPF循环加载图片导致内存溢出的解决办法

    程序场景:一系列的图片,从第一张到最后一张依次加载图片,形成“动画”. 生成BitmapImage的方法有多种: 1. var source=new BitmapImage(new Uri(" ...

  6. POI读写大数据量excel,解决超过几万行而导致内存溢出的问题

    1. Excel2003与Excel2007 两个版本的最大行数和列数不同,2003版最大行数是65536行,最大列数是256列,2007版及以后的版本最大行数是1048576行,最大列数是16384 ...

  7. String的replace导致内存溢出

    从一次内存溢出来看JDK的String应该怎么用 背景 JDK在String类中给我们提供的API,replace是个使用频率很高的的方法.因为他可以对字符串内容进行替换,只需要输入替换字符串和被替换 ...

  8. Restful规则及JPA导致内存溢出

    HTTP动词 对于资源的具体操作类型,由HTTP动词表示. 常用的HTTP动词有下面五个(括号里是对应的SQL命令). GET(SELECT):从服务器取出资源(一项或多项). POST(CREATE ...

  9. go-处理字符串导致内存溢出

    今日用go来做字符的“+”连接操作,每次连接的字符串大致有10M左右,循环连接100次,直接导致go内存溢出了. // Text project main.go package main import ...

随机推荐

  1. docker中ubuntu源更新慢加速 换为国内源 Debian10源

    本来以为是Ubuntu打包的镜像,换了阿里源老是报错100公钥不可用,结果发现是Debian的操作系统,换位Debian的操作系统打包的,换位Debian的源即可 #源如果使用错误也会报错,没有Deb ...

  2. 太赞了!Python竟可以轻松实现音频格式无损转换

    大家好,我是辰哥 辰哥在平时处理音频格式的时候,需要去下载各种音频处理软件(专业一点的软件还要收费),掌握Python技术的我们,知道Python是万能的(哈哈哈,开个玩笑).今天辰哥就来教大家用Py ...

  3. GO学习-(36) Go语言在select语句中实现优先级

    Go语言在select语句中实现优先级 Go语言在select语句中实现优先级 select语句介绍 Go 语言中的 select语句用于监控并选择一组case语句执行相应的代码.它看起来类似于swi ...

  4. GO学习-(3) VS Code配置Go语言开发环境

    VS Code配置Go语言开发环境 VS Code配置Go语言开发环境 说在前面的话,Go语言是采用UTF8编码的,理论上使用任何文本编辑器都能做Go语言开发.大家可以根据自己的喜好自行选择.编辑器/ ...

  5. Java 程序 关于Properties 类使用Store方法时不能会覆盖以前Properties 文件的内容

    F:\\Demo.properties 文件内容: #\u65B0\u589E\u4FE1\u606F#Wed Sep 14 11:16:24 CST 2016province=广东tt=近蛋city ...

  6. TVM Reduction降低算力

    TVM Reduction降低算力 这是有关如何降低算力TVM的介绍材料.像sum / max / min这样的关联约简运算符是线性代数运算的典型构造块. 本文将演示如何降低TVM算力. from _ ...

  7. 国内操作系统OS分析(上)

    国内操作系统OS分析(上) 一.操作系统(OS)概述 操作系统(OS,Operating System),是管理.控制计算机软硬件资源的计算机程序,并为用户提供一个与系统交互的操作界面.OS是配置在计 ...

  8. TensorRT IRNNv2Layer

    TensorRT IRNNv2Layer IRNNv2Layer层实现递归层,如递归神经网络(RNN).门控递归单元(GRU)和长短期记忆(LSTM).支持的类型有RNN.GRU和LSTM.它执行一个 ...

  9. python+selenium基础篇,cookie绕过验证码小案例

    1.绕过验证码有许许多多的方法,笔者在此介绍其中的一个小方法,原理其实就是获取已登陆了之后的凭证(会话保存在本地的cookie中)再打开另一个页面的使用 2.F12(浏览器开发者调试工具)可以查看的需 ...

  10. 6, java数据结构和算法: 栈的应用, 逆波兰计算器, 中缀表达式--> 后缀表达式

    直接上代码: public class PolandCalculator { //栈的应用:波兰计算器: 即: 输入一个字符串,来计算结果, 比如 1+((2+3)×4)-5 结果为16 public ...