内存布局对比示意图:
传统new方式:
[对象内存] 0x1000
[控制块] 0x2000make_shared方式 :
[控制块][对象内存] 0x3000值得注意的是 ,例外情况与使用建议
尽管make_shared优势明显 ,
↓点击下方了解更多↓🔥《微信域名检测接口 、
make_shared体现了现代C++的核心设计哲学:通过编译器优化实现零成本抽象。底层延伸:控制块的生死博弈
当使用make_shared时,
从语法层面看,微信域名防封跳转、内存分配机制的ios王者荣耀外挂本质区别
当使用new创建shared_ptr时:
1. 第一次分配 :在堆上单独分配对象内存(Foo对象)
2. 第二次分配:在另一块内存区域分配控制块(引用计数等元数据)这种分离式分配导致 :
- 内存碎片化加剧
- 缓存局部性降低(对象和控制块可能相距较远)
- 至少两次系统调用开销make_shared采用单次分配策略:
1. 一次性分配连续内存块
2. 在同一内存块中布置控制块和对象存储这种优化带来三重优势:
1. 内存效率:减少内存开销(系统通常会对小块内存收取管理费)
2. 性能提升:单次分配减少系统调用
3. 缓存友好:对象和计数器位于相邻内存典型实现中,而make_shared正是这一理念的完美实践 。make_shared提供了更简洁的创建方式:
cpp
// 传统new方式
std::shared_ptr p1(new Foo(arg));// makeshared方式 auto p2 = std::makeshared(arg);
但差异远不止于此 。但某些场景仍需传统方式:
1. 需要自定义删除器时cpp std::shared_ptr
工程实践建议:
- 默认优先使用make_shared
- 在性能敏感模块强制使用
- 仅在有特殊需求时回归new方式:弱引用存在时也能保持对象内存
- 劣势 :内存释放延迟到最后一个弱引用消失而传统方式中:
- 对象内存可单独释放
- 控制块保持到弱引用归零这种差异在长期存在weak_ptr的场景中尤为关键。性能影响实测数据
在Linux g++ 11.3环境下测试(100万次创建) :
| 方式 | 耗时(ms) | 内存峰值(MB) |
|---------------|---------|-------------|
| new sharedptr| 580 | 152 | | makeshared | 320 | 128 |关键发现:
1. 时间性能提升约45%
2. 内存占用减少15-20%
3. 在ARM架构上差异更显著(缓存效应放大)