智能指针一定智能吗?答案是否定的。要看场景。智能指针随意释放所照成的内存被回收可能会存在很多问题。 讲一个场景,有一个服务需要从磁盘上加载数据到hash表,这个hash表的数据比较大,大约占30G内存。机器的内存目前不太够,只预留了大约服务所占最大内存的2倍。同时,该函数会每小时reload一次。但是可能会在多线程里面并发调用。
目前代码如下:
//其它线程会通过调用get函数来获取这个数据管理对象
std::shared_ptr<DataManager> get(){
std::lock_guard<std::mutex> g(_mu);
return _obj;
}
//reload线程会通过这个函数来重新加载新的数据
int reload(const std::string& file) {
_mu.lock();
if (status == true) {
_mu.unlock();
return -2;
}
status = true;
_mu.unlock();
auto o = std::make_shared<DataManager>(Config::instance().server.data_count);
if (0 != o->load(file)) {
_mu.lock();
status = false;
_mu.unlock();
return -1;
}
_mu.lock();
_obj = o;
status = false;
_mu.unlock();
return 0;
}
上面代码有啥问题呢?
平时我们在使用智能指针的,很少自己去释放智能指针所持有的对象。总是靠智能指针自己去释放。我们都知道,智能指针的生命周期是当智能指针的引用计数减为0时,所持有的对象也需要被释放。
那么,上面的函数的并发的时候,可能会有个大坑。_obj = o 这一行,因为此时_obj所持有的对象在这里可能无人持有了,要释放了,如果数据量比较大,释放的时间会比较慢,导致持有_mu的锁时间会比较长。
修改之后的代码如下:
int reload(const std::string& file) {
_mu.lock();
if (status == true) {
_mu.unlock();
return -2;
}
status = true;
_mu.unlock();
auto o = std::make_shared<DataManager>(Config::instance().server.data_count);
if (0 != o->load(file)) {
o = nullptr;
_mu.lock();
status = false;
_mu.unlock();
return -1;
}
_mu.lock();
std::shared_ptr<DataManager> tmp = _obj; //此行代码是关键。
_obj = o;
status = false;
_mu.unlock();
return 0;
}
所以,在使用智能指针的时候,一定要记得,它是在啥时候被释放掉的。