发现问题
前些日子维护编写的通讯服务器时遇到了这么一个问题:在通讯服务器里有一个数据库连接池,为他人提供数据库连接服务,结果发现在使用过程中连接有时会耗尽,这个问题通过调试跟踪发现,有“客户”在使用数据库连接时,总是不释放连接(已提供了释放连接的方法)。其实问题很好解决,找出未释放连接的那个“客户”然后按照GetConnection,ReleaseConnection的方式来正确调用就可以了。
解决问题?
但是找出那个“客户”很容易吗?看看我们的整个系统吧,多达五个子系统插件在使用这个服务,而且其中的数据库连接调用很多,这样找可费了大劲了。在经过大量的代码审核后,终于找出未释放连接的那个客户,解决了这个问题。
思考之下,作为一个关键的公共服务是不是可以做相应优化来应对这种“客户”犯下的错误。
采用RAII机制,把释放链接的那个方法也写入析构函数中
举例(采用伪码加不标准类写法方式,主要是说明思路;参考effective c++章节2 构造/析构)
class ConnectionPool
{
public:
...
~ConnectionPool( void);
{
if (!bRelease)
{
Release连接();
}
}
void ReleaseConnection()
{
Release连接();
bRelease = true;
}
private:
bool bRelease; (初始化为 false)
};
{
public:
...
~ConnectionPool( void);
{
if (!bRelease)
{
Release连接();
}
}
void ReleaseConnection()
{
Release连接();
bRelease = true;
}
private:
bool bRelease; (初始化为 false)
};
这样”客户“如果是采用栈或智能指针实例化的对象来使用服务,即使忘记释放连接都可以利用RAII机制安全释放;
但是如果”客户“直接用new出的对象使用服务忘记释放连接呢,又回到了最先遇到的问题上,在一大推调用里找究竟是谁未释放连接。继续解决:
既然现在我们的困扰集中在找违规”客户“的麻烦上,想想图书馆借书,谁借去了必须把他的名字登记下来,谁谁谁借走了这本书,到时候即使他不还,咱也有办法找到他让他给咱还回来。于是我们可以再改造一下这个服务,在每个”客户“获得连接时都传入他的标识然后把这个连接和标识捆绑起来。这样,哪个”客户“未释放连接一目了然了吧,立马找到他让他改正。OK,快速解决。
本文转自永远的朋友博客51CTO博客,原文链接http://blog.51cto.com/yaocoder/838130如需转载请自行联系原作者
yaocoder