std::shared_ptr<T>
的内存开销
std::shared_ptr<T>
element_type* _M_ptr; // Contained pointer. sizeof(intptr_t) 字节
__shared_count<_Lp> _M_refcount; // Reference counter. sizeof(intptr_t) 字节
_Sp_counted_base<_Lp>* _M_pi;
std::_Sp_counted_base<__default_lock_policy>
// vtable pointer // sizeof(intptr_t) 字节
_Atomic_word _M_use_count; // #shared 4 字节,实际上是 int 类型
_Atomic_word _M_weak_count; // #weak + (#shared != 0) 4 字节
其中,记录 use count 是为了判断什么时候可以释放共享指针指向的对象;记录 weak count 是为了判断什么时候可以安全释放控制块本身。即便是共享指针指向对象已经被释放(use count 归零),也可能有弱指针会尝试转换成共享指针,因此应该保证这些弱指针能安全查询控制块。还有一点,如果用 std::make_shared
创建共享指针,use count 归零而 weak count 不归零时,共享对象只是被析构,其内存会等到 weak count 归零时一起被释放。可以参考 https://stackoverflow.com/a/49585948/ 。
在 64 位环境下,一个 std::shared_ptr<T>
是 16 字节(8 + 8),其中控制块的真实大小是 16 字节(4 + 4 + 8)。(在 std::shared_ptr<T>
中存储的是指向控制块的指针、而不是控制块本身,这样才能保证使用相同的控制块。)
std::_Sp_counted_base<_Lp>
的大小
不过,std::_Sp_counted_base
还支持其他的上锁策略,从 /usr/include/c++/12/bits/shared_ptr_base.h 的以下代码可以看出一共有 4 种可选的上锁类型。