对象池

Posted yuhanbo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了对象池相关的知识,希望对你有一定的参考价值。

背景:

    假设有一个Stock类,代表一只股票的价格,且每个股票有std::string唯一标识符。Stock对象是个主动对象,能不断获取股票的最新价格。为节省系统资源,每个程序每只出现的股票只有一个Stock对象。如果多处用到一只股票,那么Stock对象要被共享,如果这只股票没有被用到,那么对应的Stock对象应该被析构,以释放资源。下面设计一个StockFactory。

Version1:

代码:

1 class StockFactory : boost::noncopyable
2 {
3     public:
4         shared_ptr<Stock> get(const string& key);
5     private:
6         mutable MutexLock mutex_;
7         std::map<string, shared_ptr<Stock>> stocks_;
8 };

问题:

由于map中存放的市shared_ptr,因此Stock永远不会被析构。

Version2:

代码:

class StockFactory : boost::noncopyable
{
    public:
        shared_ptr<Stock> get(const string& key);
    private:
        mutable MutexLock mutex_;
        std::map<string, weak_ptr<Stock>> stocks_;
};

shared_ptr<Stock> StockFactory::get(const string& key)
{
    shared_ptr<Stock> pStock;
    MutexLockGuard lock(mutex_);
    weak_ptr<Stock>& wStock = stocks_[key];
    pStock = wStock.lock();
    if (!pStock)
    {
        pStock.reset(new Stock(key));
        wStock = pStock;
    }
    return pStock;
}
技术图片

问题:

造成了内存泄漏,stock_大小只增不减,stock_.size()的大小是曾经被用到的Stock对象的总数。

Version3:

代码:

class StockFactory : boost::noncopyable
{
    public:
        shared_ptr<Stock> get(const string& key);
    private:
        mutable MutexLock mutex_;
        std::map<string, weak_ptr<Stock>> stocks_;
        void deleteStock(Stock* stock)
        {
            if (stock)
            {
                MutexLockGuard lock(mutex_);
                stocks_.erase(stock->key());
            }
            delete stock;
        }
};

shared_ptr<Stock> StockFactory::get(const string& key)
{
    shared_ptr<Stock> pStock;
    MutexLockGuard lock(mutex_);
    weak_ptr<Stock>& wStock = stocks_[key];
    pStock = wStock.lock();
    if (!pStock)
    {
        pStock.reset(new Stock(key), [this](auto stock) {
            deleteStock(stock);
        });
        wStock = pStock;
    }
    return pStock;
}

问题:

出现了线程不安全的问题,this指针被传入lambda的deleteStock中,若StockFactory先于Stock析构,将core dump。

Version4:

代码:

class StockFactory : boost::noncopyable, public enable_shared_from_this<StockFactory>
{
    public:
        shared_ptr<Stock> get(const string& key);
    private:
        mutable MutexLock mutex_;
        std::map<string, weak_ptr<Stock>> stocks_;
        void deleteStock(Stock* stock)
        {
            if (stock)
            {
                MutexLockGuard lock(mutex_);
                stocks_.erase(stock->key());
            }
            delete stock;
        }
};

shared_ptr<Stock> StockFactory::get(const string& key)
{
    shared_ptr<Stock> pStock;
    MutexLockGuard lock(mutex_);
    weak_ptr<Stock>& wStock = stocks_[key];
    pStock = wStock.lock();
    if (!pStock)
    {
        pStock.reset(new Stock(key), [shared_from_this()](auto stock) {
            deleteStock(stock);
        });
        wStock = pStock;
    }
    return pStock;
}
技术图片

问题:

虽然能够保证在调用deleteStock时,StockFactory对象仍然“存活”,但是shared_from_this()使得StockFactory对象的声明周期被延长了。

Version5:

代码:

class StockFactory : boost::noncopyable, public enable_shared_from_this<StockFactory>
{
    public:
        shared_ptr<Stock> get(const string& key);
    private:
        mutable MutexLock mutex_;
        std::map<string, weak_ptr<Stock>> stocks_;
        void deleteStock(const weak_ptr<StockFactory>& wFactory, Stock* stock)
        {
            shared_ptr<StockFactory> factory(wFactory.lock());
            if (factory)
            {
                if (stock)
                {
                    MutexLockGuard lock(mutex_);
                    stocks_.erase(stock->key());
                }
            }
            delete stock;
        }
};

shared_ptr<Stock> StockFactory::get(const string& key)
{
    shared_ptr<Stock> pStock;
    MutexLockGuard lock(mutex_);
    weak_ptr<Stock>& wStock = stocks_[key];
    pStock = wStock.lock();
    if (!pStock)
    {
        pStock.reset(new Stock(key), [=](auto stock) {
            deleteStock(weak_ptr<StockFactory>(shared_from_this()), stock);
        });
        wStock = pStock;
    }
    return pStock;
}
技术图片

以上是关于对象池的主要内容,如果未能解决你的问题,请参考以下文章

14.VisualVM使用详解15.VisualVM堆查看器使用的内存不足19.class文件--文件结构--魔数20.文件结构--常量池21.文件结构访问标志(2个字节)22.类加载机制概(代码片段

变量的内存分析图

使用媒体播放器或声音池在片段内的 onClick 中播放声音

VSCode自定义代码片段12——JavaScript的Promise对象

VSCode自定义代码片段12——JavaScript的Promise对象

VSCode自定义代码片段——JS中的面向对象编程