成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

C++11 引入的 shared_ptr 智能指針性能對比 Raw 指針怎么樣?

開發(fā) 前端
自從C++11智能指針推出后,關(guān)于 shared_ptr 的使用,分為了兩派,一派認(rèn)為Raw指針不應(yīng)該再出現(xiàn)在代碼中,另外一派認(rèn)為要謹(jǐn)慎使用 shared_ptr, 大多數(shù)時(shí)候還是要使用Raw指針更合理。

C++11引入的智能指針(std::shared_ptr、std::unique_ptr、std::weak_ptr)通過自動(dòng)化資源管理,極大降低了內(nèi)存泄漏和懸垂指針的風(fēng)險(xiǎn)。

自從C++11智能指針推出后,關(guān)于 shared_ptr 的使用,分為了兩派,一派認(rèn)為Raw指針不應(yīng)該再出現(xiàn)在代碼中,另外一派認(rèn)為要謹(jǐn)慎使用 shared_ptr, 大多數(shù)時(shí)候還是要使用Raw指針更合理。

這里我們不討論者兩派誰正確,關(guān)注的是 shared_ptr 的性能。

shared_ptr 提供了很多便利,但是這種便利性并非沒有代價(jià)——尤其是 std::shared_ptr,其性能開銷在特定場景下可能成為瓶頸。

一、智能指針性能開銷的核心來源

1. 原子操作與引用計(jì)數(shù)

std::shared_ptr 的核心機(jī)制是引用計(jì)數(shù),其實(shí)現(xiàn)依賴于原子操作。每次拷貝或銷毀 shared_ptr 時(shí),引用計(jì)數(shù)(use_count)和弱引用計(jì)數(shù)(weak_count)都需要通過原子指令進(jìn)行增減。

原子操作雖然保證了線程安全,但其代價(jià)顯著: 

原子指令的硬件支持:現(xiàn)代CPU通過鎖緩存行(Cache Line Locking)或總線鎖(Bus Locking)實(shí)現(xiàn)原子性。例如,x86架構(gòu)的LOCK前綴指令會(huì)強(qiáng)制獨(dú)占緩存行,導(dǎo)致流水線停頓。

內(nèi)存屏障(Memory Barrier):原子操作通常伴隨內(nèi)存屏障,確保多核間的數(shù)據(jù)一致性。這會(huì)抑制編譯器和CPU的指令重排優(yōu)化,增加指令周期。

示例:引用計(jì)數(shù)的原子增減 

// 偽代碼:shared_ptr拷貝構(gòu)造時(shí)的原子操作
ControlBlock* ctrl = ptr.control_block;
atomic_increment(&ctrl->use_count);  // 原子遞增

2. 控制塊的內(nèi)存開銷

每個(gè) shared_ptr 實(shí)例需要維護(hù)一個(gè)控制塊(Control Block),包含: 

引用計(jì)數(shù)(use_count)
弱引用計(jì)數(shù)(weak_count)
刪除器(Deleter)
分配器(Allocator)

控制塊通常通過動(dòng)態(tài)內(nèi)存分配(如new)創(chuàng)建,其大小在64位系統(tǒng)下約為40字節(jié)(具體因?qū)崿F(xiàn)而異)。頻繁創(chuàng)建 shared_ptr 會(huì)導(dǎo)致堆內(nèi)存碎片化,同時(shí)增加緩存未命中的概率。 

3. 間接訪問與緩存局部性

shared_ptr的實(shí)際對象指針和控制塊指針通常是分離的。訪問對象時(shí),需要先加載控制塊指針,再通過控制塊訪問對象。這種兩級(jí)間接訪問破壞了數(shù)據(jù)的空間局部性,導(dǎo)致CPU緩存效率降低。 

對比:原始指針 vs. shared_ptr 

// 原始指針:直接訪問
int* raw = new int(42);
int value = *raw;  // 一次內(nèi)存訪問

// shared_ptr:間接訪問
std::shared_ptr<int> shared = std::make_shared<int>(42);
int value = *shared;  // 先訪問控制塊,再訪問對象(可能兩次內(nèi)存訪問)

二、量化性能開銷:基準(zhǔn)測試與分析

1. 單線程環(huán)境下的開銷

通過對比shared_ptr、unique_ptr和原始指針的操作耗時(shí),可以直觀量化性能差異。 

測試代碼片段(使用Google Benchmark): 

static voidBM_RawPtr(benchmark::State& state){
    for (auto _ : state) {
        int* p = newint(42);
        delete p;
    }
}
BENCHMARK(BM_RawPtr);

staticvoidBM_UniquePtr(benchmark::State& state){
    for (auto _ : state) {
        auto p = std::make_unique<int>(42);
    }
}
BENCHMARK(BM_UniquePtr);

staticvoidBM_SharedPtr(benchmark::State& state){
    for (auto _ : state) {
        auto p = std::make_shared<int>(42);
    }
}
BENCHMARK(BM_SharedPtr);

結(jié)果(x86-64, GCC 12.2, -O2優(yōu)化): 

操作

耗時(shí)(ns/op)

Raw Pointer

15

std::unique_ptr

16

std::shared_ptr

45

結(jié)論:shared_ptr的構(gòu)造/析構(gòu)開銷是原始指針的3倍,主要來自控制塊分配和原子操作。 

2. 多線程環(huán)境下的爭用(Contention)

當(dāng)多個(gè)線程頻繁操作同一shared_ptr時(shí),原子操作的緩存一致性協(xié)議(如MESI)會(huì)導(dǎo)致嚴(yán)重的性能下降。 

測試場景: 

10個(gè)線程并發(fā)增加/減少shared_ptr的引用計(jì)數(shù)。

對比無爭用(每個(gè)線程操作獨(dú)立shared_ptr)和高爭用(所有線程操作同一shared_ptr)。

結(jié)果(AMD EPYC 7763, 64核): 

場景

吞吐量(ops/ms)

無爭用

1,200,000

高爭用

12,000

結(jié)論:高爭用下性能下降100倍,原子操作的緩存行乒乓(Cache Line Ping-Pong)是主因。(當(dāng)多個(gè)線程頻繁更新某一緩存行中的數(shù)據(jù)時(shí),緩存系統(tǒng)可能需要不斷地將數(shù)據(jù)從一個(gè)核心的緩存同步到另一個(gè)核心的緩存,這個(gè)過程就像乒乓球一樣在緩存之間來回傳遞,導(dǎo)致性能降低)

三、底層機(jī)制:從C++標(biāo)準(zhǔn)到硬件架構(gòu)

1. 原子操作的實(shí)現(xiàn)細(xì)節(jié)

C++標(biāo)準(zhǔn)要求 shared_ptr 的引用計(jì)數(shù)操作是線程安全的,因此編譯器會(huì)生成特定的原子指令。以x86-64為例: 

atomic_increment對應(yīng)LOCK XADD指令。

LOCK XADD 是原子加法和交換指令。它會(huì)確保在多個(gè)處理器核心之間同步操作,避免數(shù)據(jù)競爭。
std::shared_ptr 的引用計(jì)數(shù)增加時(shí),會(huì)使用這種指令

atomic_decrement對應(yīng)LOCK SUB指令。

LOCK SUB 是帶鎖的減法指令,保證了引用計(jì)數(shù)的減少操作是原子的,防止多個(gè)線程同時(shí)修改引用計(jì)數(shù)時(shí)發(fā)生競態(tài)條件。

2. 控制塊的內(nèi)存布局

典型的shared_ptr控制塊布局(以libstdc++實(shí)現(xiàn)為例): 

struct ControlBlock {
    std::atomic<long> use_count;  // 8字節(jié)
    std::atomic<long> weak_count; // 8字節(jié)
    Deleter* deleter;             // 8字節(jié)
    Allocator* allocator;         // 8字節(jié)
    void* object_ptr;             // 8字節(jié)
};

總大小:40字節(jié)(64位系統(tǒng))。若對象較小(如int),控制塊的內(nèi)存開銷可能超過對象本身。 

3. 緩存局部性的影響

現(xiàn)代CPU的L1緩存行通常為64字節(jié)。若 shared_ptr 的控制塊和對象分散存儲(chǔ),訪問對象時(shí)可能需要加載兩個(gè)不同的緩存行,導(dǎo)致吞吐量下降。 

優(yōu)化示例:std::make_shared將對象和控制塊分配在連續(xù)內(nèi)存中,提高緩存局部性: 

auto p = std::make_shared<int>(42);  // 對象和控制塊單次分配
auto q = std::shared_ptr<int>(new int(42));  // 兩次分配(對象+控制塊)

四、實(shí)際場景中的性能問題案例

1. 游戲引擎中的實(shí)體管理

某游戲引擎使用 shared_pt r管理游戲?qū)嶓w(Entity),每個(gè)實(shí)體包含多個(gè)組件(Component)。在每秒60幀的更新頻率下,頻繁的 shared_ptr 拷貝導(dǎo)致CPU耗時(shí)增加15%。

優(yōu)化方案: 

改用std::unique_ptr + 手動(dòng)生命周期管理。

使用對象池(Object Pool)減少動(dòng)態(tài)分配。

2. 高頻交易系統(tǒng)的消息傳遞

一個(gè)高頻交易系統(tǒng)使用 shared_ptr 傳遞市場數(shù)據(jù)消息。在峰值負(fù)載下,原子操作的爭用導(dǎo)致延遲從2微秒飆升至50微秒。

優(yōu)化方案: 

改用無鎖(Lock-Free)數(shù)據(jù)結(jié)構(gòu)和原始指針。

使用線程局部存儲(chǔ)(TLS)避免跨線程爭用。

3. 分布式系統(tǒng)的節(jié)點(diǎn)通信

某分布式系統(tǒng)使用 shared_ptr 管理網(wǎng)絡(luò)連接對象。在10,000個(gè)并發(fā)連接下,控制塊內(nèi)存占用超過1GB。

優(yōu)化方案: 

使用std::weak_ptr替代非擁有性引用。

自定義刪除器復(fù)用控制塊內(nèi)存。

五、優(yōu)化策略與實(shí)踐

1. 優(yōu)先使用std::unique_ptr

適用場景:獨(dú)占所有權(quán),無需共享。

優(yōu)勢:零額外開銷,性能等同原始指針。

示例:

auto resource = std::make_unique<DatabaseConnection>();
transfer_ownership(std::move(resource));  // 顯式所有權(quán)轉(zhuǎn)移

2. 減少 shared_ptr 的拷貝

使用const&傳遞:避免不必要的引用計(jì)數(shù)增減。

void process(const std::shared_ptr<Data>& data) { /* ... */ }

移動(dòng)語義:用std::move轉(zhuǎn)移所有權(quán)。

auto p1 = std::make_shared<int>(42);
auto p2 = std::move(p1);  // 無原子操作

3. 控制塊分配優(yōu)化

使用std::make_shared:合并對象和控制塊的內(nèi)存分配。

auto p = std::make_shared<Object>(args);  // 推薦
auto q = std::shared_ptr<Object>(new Object(args));  // 不推薦

4. 避免多線程爭用

線程局部存儲(chǔ)(TLS):為每個(gè)線程分配獨(dú)立shared_ptr。

thread_local std::shared_ptr<Cache> local_cache = create_cache();

總結(jié)

原始指針:性能更高,因?yàn)闆]有引用計(jì)數(shù)和線程安全管理的開銷,但缺乏自動(dòng)內(nèi)存管理和線程安全,容易導(dǎo)致內(nèi)存泄漏或多線程錯(cuò)誤。

shared_ptr:提供了自動(dòng)內(nèi)存管理和線程安全,但有一定的性能開銷,尤其是在引用計(jì)數(shù)操作和多線程環(huán)境下。

責(zé)任編輯:武曉燕 來源: CppPlayer
相關(guān)推薦

2024-03-01 16:43:48

C++11智能指針內(nèi)存

2023-11-17 11:48:08

智能指針C++

2010-12-17 10:07:59

2010-02-05 14:36:20

C++智能指針

2015-07-27 11:34:03

Linux內(nèi)核指針

2021-09-09 17:05:36

C++智能指針語言

2021-08-11 09:01:48

智能指針Box

2024-12-26 10:45:08

2021-07-29 06:09:05

萬能指針C語言void

2023-12-20 12:40:51

C++RAII編程

2010-01-27 14:18:41

Android智能指針

2024-05-29 13:21:21

2021-07-30 05:12:54

智能指針C++編程語言

2011-07-01 14:28:47

Qt 指針

2024-01-24 11:44:44

C++智能指針開發(fā)

2021-01-13 06:58:35

C語言函數(shù)指針

2025-06-17 08:10:00

智能指針C++代碼

2018-03-01 15:20:59

iOS開發(fā)多線程

2022-02-08 09:09:45

智能指針C++

2014-01-24 09:49:01

C++指針
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 一区二区三区视频 | 久久天堂 | 中文字幕精品一区二区三区精品 | 日本亚洲欧美 | 中文字幕av网站 | 超碰男人天堂 | 五月婷婷 六月丁香 | 国产成人麻豆免费观看 | 国产精品成人在线观看 | 日本一区二区在线视频 | 在线视频 欧美日韩 | 欧美日韩综合精品 | 亚洲福利在线视频 | 天堂资源 | 美女日皮网站 | 99在线资源 | 亚洲欧美一区二区三区在线 | 男女羞羞免费视频 | 久久精品91久久久久久再现 | 中文字幕亚洲区 | 日韩精品一区二区三区四区 | 国产高清免费 | 国产在线精品一区二区 | 不卡一区二区三区四区 | 日韩日b视频 | 欧美成人影院 | 欧区一欧区二欧区三免费 | 欧美日韩精品一区二区三区蜜桃 | 美女国内精品自产拍在线播放 | 成人一区二区三区在线观看 | 欧美久久久久久久久中文字幕 | 亚洲综合在线播放 | 欧美成人精品在线观看 | 国产婷婷色综合av蜜臀av | 噜噜噜噜狠狠狠7777视频 | 亚洲精品日韩精品 | 欧美精品一区二区三区在线 | 国产精品久久久久久久久久久新郎 | 亚洲一区二区免费视频 | 成人美女免费网站视频 | 亚洲精品乱码久久久久v最新版 |