PDO之MySql持久化自动重连导致内存溢出
前言
最近项目需要一个常驻内存的脚本来执行队列程序,脚本完成后发现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持久化自动重连导致内存溢出的更多相关文章
- php查询mysql返回大量数据结果集导致内存溢出的解决方法
web开发中如果遇到php查询mysql返回大量数据导致内存溢出.或者内存不够用的情况那就需要看下MySQL C API的关联,那么究竟是什么导致php查询mysql返回大量数据时内存不够用情况? 答 ...
- 图片--Android加载图片导致内存溢出(Out of Memory异常)
Android在加载大背景图或者大量图片时,经常导致内存溢出(Out of Memory Error),本文根据我处理这些问题的经历及其它开发者的经验,整理解决方案如下(部分代码及文字出处无法考证) ...
- 添加IFrame导致内存溢出的解决过程(IE浏览器,目前发现了原因,还未解决)
1. 现象 每次动态添加iframe时,iexplore.exe进程占据的内存都会增加(大概10M左右),不会自动释放,最终导致内存溢出 2. 解决过程 经过网络的一番搜索,基本上给出的解决方案是 ...
- Android加载图片导致内存溢出(Out of Memory异常)
Android在加载大背景图或者大量图片时,经常导致内存溢出(Out of Memory Error),本文根据我处理这些问题的经历及其它开发者的经验,整理解决方案如下(部分代码及文字出处无法考证) ...
- WPF循环加载图片导致内存溢出的解决办法
程序场景:一系列的图片,从第一张到最后一张依次加载图片,形成“动画”. 生成BitmapImage的方法有多种: 1. var source=new BitmapImage(new Uri(" ...
- POI读写大数据量excel,解决超过几万行而导致内存溢出的问题
1. Excel2003与Excel2007 两个版本的最大行数和列数不同,2003版最大行数是65536行,最大列数是256列,2007版及以后的版本最大行数是1048576行,最大列数是16384 ...
- String的replace导致内存溢出
从一次内存溢出来看JDK的String应该怎么用 背景 JDK在String类中给我们提供的API,replace是个使用频率很高的的方法.因为他可以对字符串内容进行替换,只需要输入替换字符串和被替换 ...
- Restful规则及JPA导致内存溢出
HTTP动词 对于资源的具体操作类型,由HTTP动词表示. 常用的HTTP动词有下面五个(括号里是对应的SQL命令). GET(SELECT):从服务器取出资源(一项或多项). POST(CREATE ...
- go-处理字符串导致内存溢出
今日用go来做字符的“+”连接操作,每次连接的字符串大致有10M左右,循环连接100次,直接导致go内存溢出了. // Text project main.go package main import ...
随机推荐
- Qt 中英文切换
一.前言 软件面向不同国籍用户时,需要显示不同语言的操作界面,Qt提供语言家可翻译为不同语言类型,方便软件走向国际化. 二.功能实现 1.翻译文件制作 1)在pro文件中添加生成中英文翻译过渡文件(. ...
- unity ab包打包和加载的简单学习示例
闲着没事结合项目看了下unity AssetBundle打包和使用,写了一些测试例子,需要的可以拿去,导入一个空项目即可 链接:https://pan.baidu.com/s/1H85dnMNkRoW ...
- 第5讲 | 从物理层到MAC层:如何在宿舍里自己组网玩联机游戏?
第一层(物理层) 水晶头要做交叉线,用的就是所谓的 1-3.2-6 交叉接法. 有一个叫做 Hub 的东西,也就是集线器.这种设备有多个口,可以将宿舍里的多台电脑连接起来.但是,和交换机不同,集线器没 ...
- [leetcode] 75. 分类颜色(常数空间且只扫描一次算法)
75. 分类颜色 我们直接按难度最高的要求做:你能想出一个仅使用常数空间的一趟扫描算法吗? 常数空间 只能扫描一趟.注意,是一趟,而不是O(n) 题中只会出现3个数字:0,1,2.换句话说,0肯定在最 ...
- GO语言面向对象03---接口与断言
接口的实现 package main import "fmt" type Animal interface { //出生 SayHelloWord() //死亡 Godie() / ...
- python基础知识笔记(一)
一.变量 可以是字母.数字(不能作为开头).下划线. 自定义的常量名一般全部大写. na = "liu" na2 = na print("my na is ", ...
- Vue&Element 前端应用开发之菜单和路由的关系
我们一般的应用系统,菜单是很多功能界面的入口,菜单为了更好体现功能点的设置,一般都是动态从数据库生成的,而且还需要根据用户角色的不同,过滤掉部分没有权限的菜单:在Vue&Element的纯前端 ...
- 如何挑选深度学习 GPU?
如何挑选深度学习 GPU? 深度学习是一个对计算有着大量需求的领域,从一定程度上来说,GPU的选择将从根本上决定深度学习的体验.因此,选择购买合适的GPU是一项非常重要的决策.那么2020年,如何选择 ...
- 如何选择视觉CV光源颜色
如何选择视觉CV光源颜色 一.光源颜色分类 光源颜色的选择对机器视觉光源有什么影响及意义呢,常用的光源颜色有白色(W).蓝色(B).红色(R).绿色(G).红外光(IR).紫外光(UV),这六种颜色. ...
- Spring Cache缓存技术,Cacheable、CachePut、CacheEvict、Caching、CacheConfig注解的使用
前置知识: 在Spring Cache缓存中有两大组件CacheManager和Cache.在整个缓存中可以有多个CacheManager,他们负责管理他们里边的Cache.一个CacheManage ...