CPU架構、三級緩存以及內存優化屏障

目錄

一、三級緩存和內存布局

二、CPU架構

(1)SMP對稱對處理器架構

(2)NUMA非統一內存架構

三、RCU機制在內核中的體現

四、內存優化屏障

(1)編譯器、CPU優化

(2)優化的問題和解決辦法

(3)volatile關鍵字


????????在學習Linux或者c++的時候,經常會看到緩存、內存、寄存器這樣的字眼。只知道他們都是用于存儲數據、指令的,且有效率之分,但是具體的框圖并不了解。本篇文章以此為基礎,延伸到CPU的架構等問題。

一、三級緩存和內存布局

? ? ? ? 我們知道當前主流的計算機是符合馮諾依曼體系架構的。內存位于所有結構的中心,任何外設想要進行數據交換都必須先把數據、指令交給內存,然后分別從內存中讀取。

? ? ? ? 如下圖所示:

有了這樣一份基礎架構,我們就能更好的理解CPU運行的時候,是如何從內存得到指令和數據的。

????????即調度器把某個進程的PCB給到CPU,然后CPU根據PCB里面的地址找到物理內存要數據、指令,通過三級緩存和寄存器逐級交付,最終傳遞給CPU的過程。

二、CPU架構

(1)SMP對稱對處理器架構

????????SMP(Symmetric Multi - Processing)架構中,多個 CPU 核心共享統一的內存空間、I/O 設備等系統資源,并且所有 CPU 核心的地位平等,它們可以無差別地訪問內存、外設等,操作系統可以將任務動態分配到任意一個 CPU 核心上執行。

優點

?
  • 易于編程:對于開發者來說,SMP 架構下的編程模型相對簡單,因為所有 CPU 核心對系統資源的訪問方式基本相同,不需要考慮太多復雜的資源分配和訪問差異問題。
  • 負載均衡:操作系統能夠方便地在各個 CPU 核心之間進行任務調度,實現負載均衡,充分利用各個核心的計算能力。
?

缺點

?
  • 內存訪問瓶頸:隨著 CPU 核心數量的增加,所有核心都訪問同一個內存空間,會導致內存總線的競爭加劇,從而形成性能瓶頸。
  • 可擴展性受限:由于共享內存等資源的限制,當核心數量增加到一定程度時,性能提升不明顯甚至會下降。

(2)NUMA非統一內存架構

????????NUMA(Non - Uniform Memory Access)架構中,多個 CPU 核心被劃分成不同的節點,每個節點都有自己的本地內存,同時也可以訪問其他節點的內存,但訪問本地內存的速度要比訪問遠程(其他節點)內存的速度快。操作系統需要考慮內存分配與 CPU 核心的位置關系,以提高性能。

優點

?
  • 高可擴展性:通過將內存分配到不同節點,減少了內存訪問沖突,使得系統在增加 CPU 核心數量時,依然能夠保持較好的性能擴展性。
  • 局部性原理利用:可以將數據和任務分配到對應的節點,充分利用本地內存訪問速度快的優勢,提高整體性能。
?

缺點

?
  • 編程復雜度增加:開發者需要考慮內存的本地性問題,在編程時需要手動管理內存分配,以確保數據在合適的節點上,否則可能導致性能下降。
  • 管理復雜:操作系統需要更復雜的資源管理和調度策略,來平衡各個節點的負載和優化內存訪問。

三、RCU機制在內核中的體現

? ? ? ? RCU本質只是一種提高讀寫效率的鎖。但是在Linux中廣泛的用到。比如在task_struct中,我們曾說到有進程的ID、調度策略、用戶地址空間指針等等各種成員。內核中存在著大量的鏈表結構,無論是調度器就緒隊列,還是全局進程鏈表、子進程鏈表。這些鏈表操作往往涉及到大量的讀,而對寫性能要求不高。此時RCU機制就能發揮到極致。

? ? ? ? 下面我們來看看內核中的RCU機制引申出的鏈表rcu操作。

// 安全的節點插入(使用內存屏障)
void safe_add_node(struct my_node *new) {// 1. 完成所有數據初始化new->data = 100;// 2. 使用寫內存屏障(確保之前的寫操作對其他CPU可見)smp_wmb();// 3. 原子更新鏈表指針(使新節點對讀操作可見)list_add_tail_rcu(&new->list, &my_list);
}// 安全的節點刪除(使用內存屏障)
void safe_delete_node(struct my_node *node) {// 1. 原子更新鏈表指針(從鏈表移除節點)list_del_rcu(&node->list);// 2. 使用讀內存屏障(確保后續同步操作的順序)smp_rmb();// 3. 等待寬限期結束(確保沒有讀操作引用舊節點)synchronize_rcu();// 4. 安全釋放內存kfree(node);
}// 安全的鏈表遍歷(無鎖讀)
void safe_traverse(void) {struct my_node *node;rcu_read_lock();  // 標記讀臨界區開始// 使用 RCU 安全遍歷宏(確保指針解引用安全)list_for_each_entry_rcu(node, &my_list, list) {// 讀操作期間,數據可能被修改,但保證可見性順序printk("Data: %d\n", node->data);}rcu_read_unlock();  // 標記讀臨界區結束
}

????????可以看到這個rcu插入鏈表節點的函數,不僅僅是更新了鏈表的節點,還調用了內存屏障函數,保證了編譯器和CPU的優化不會亂序,讓別的進程要么看到數據最新的新節點,要么看不到該節點,不存在已經插入到鏈表中而數據后更新的問題。

四、內存優化屏障

(1)編譯器、CPU優化

? ? ? ? 我們寫好了一個程序交給編譯器編譯、或者交給CPU運行的時候,可能與我們想象中一條條地執行不同,無論是編譯器還是CPU都會采取一定的優化策略,讓性能進一步提高。

? ? ? ? 比如編譯器優化:把顯而易見的代碼直接求出結果,編譯成二進制。這樣能減少CPU運行的時間。

優化原理

? ? ? ? 把顯而易見的步驟直接在編譯環節得到結果,減少CPU運行次數。

?
  • 減少循環次數(原循環執行 n 次,展開后執行 n/4 次),降低分支預測失敗和循環開銷(如計數器更新、條件判斷)。
  • 增加指令級并行(ILP):多條加法指令可同時在 CPU 流水線中執行。

????????再比如CPU運行優化:

優化原理

? ? ? ? CPU從內存讀取一個數據需要時間,這個時間如果傻等就白白浪費了,所以選擇同時讀取一堆,重疊掉這個等待時間。

?
  • SIMD(單指令多數據):利用 CPU 的向量寄存器(如 AVX2 的 256 位寄存器)同時處理多個數據。
  • 數據并行:一條指令完成 8 個浮點數加法,吞吐量提升 8 倍(理論值)。

(2)優化的問題和解決辦法

? ? ? ? CPU和編譯器的亂序優化,本質上是為了提高運行效率。但是也導致了一個結果:可能導致不同線程錯誤的讀到類似空指針的錯誤。

舉個例子:

// 期望的鏈表插入函數
void incorrect_add_node(struct my_node *new) {// 初始化新節點new->data = 42;// 設置數據字段(可能被重排序到指針更新之后)new->data = 100;  // 危險:可能在節點可見后才被更新// 將新節點連接到鏈表中list_add_tail_rcu(&new->list, &my_list);}

被優化后的:

// 錯誤的鏈表插入函數(無內存屏障)
void incorrect_add_node(struct my_node *new) {// 初始化新節點new->data = 42;// 先將新節點連接到鏈表中list_add_tail_rcu(&new->list, &my_list);// 然后設置數據字段(可能被重排序到指針更新之后)new->data = 100;  // 危險:可能在節點可見后才被更新
}

即使關閉了所有的優化,還是有可能出現問題:

正確的做法是在中間部分添加內存屏障:這里保證了先初始化數據,再更新鏈表指針。讓其他線程要么看不到更新的鏈表節點,要么看到就是數據已經更新的完全體。

// 正確的鏈表插入函數(使用內存屏障)
void correct_add_node(struct my_node *new) 
{// 1. 先完成所有數據初始化new->data = 100;// 2. 使用寫內存屏障確保數據初始化對其他CPU可見smp_wmb();  // 寫內存屏障,確保之前的寫操作都完成// 3. 最后更新鏈表指針,使新節點對讀操作可見list_add_tail_rcu(&new->list, &my_list);
}

????????最后,Linux中的內存屏障有許多種,其中通用屏障開銷最大,我們最好根據請款選擇合適的內存屏障。

(3)volatile關鍵字

? ? ? ? 正如我們上面所說的優化有亂序的問題,CPU在讀取某個變量的值的時候也會存在優化。當寄存器中恰好存儲的就是該變量的值的時候(頻繁訪問某一個變量很有可能出現這種情況),cpu往往會直接從該寄存器中讀取。

? ? ? ? 而寄存器更新的原則是覆蓋式更新,即讀新的數據,寄存器中原本沒有,于是從L1、L2等緩存中覆蓋寫入到寄存器。如果該變量剛好就在寄存器,則可能讀到舊值(緩存中的值已經發生了改變)。

? ? ? ? volatile關鍵字的作用就是,禁止編譯器把變量緩存到寄存器中,強制要求cpu每次必須在內存/緩存中讀取該變量的值,從而保證了值的實時性。

????????不過他僅僅是解決?“編譯器和硬件緩存導致的舊值讀取”?的輕量級工具,但僅適用于簡單場景。復雜的多線程 / 硬件同步,必須用更強大的原語(原子操作、內存屏障、鎖)。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/89380.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/89380.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/89380.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

HarmonyOS從入門到精通:動畫設計與實現之九 - 實用動畫案例詳解(下)

HarmonyOS動畫開發實戰(九):實用動畫案例詳解(下) 在上篇中,我們圍繞加載動畫、點贊反饋、下拉刷新等核心交互場景,探討了如何通過動畫提升用戶體驗。本篇將聚焦界面元素動效與特殊場景動畫&…

Node.js 聊天內容加密解密實戰教程(含緩存密鑰優化)

一、技術方案說明 本方案采用以下技術組合: 加密算法:AES-256-GCM(認證加密,防止篡改)密鑰派生:PBKDF2(10萬次迭代)緩存機制:內存緩存 定期輪換安全特性:隨機…

信息安全基礎專業面試知識點(上:密碼學與軟件安全)

密碼學DES加密流程56比特長度的密鑰K, 分組長度64比特,密文64比特初始置換 (IP):將輸入的64位明文塊進行置換,打亂其順序。分成左右兩半: 將置換后的64位數據分成左右兩部分,每部分32位。16輪迭代加密: 這是DES的核心&#xff0c…

Windows Server 2025 黃金dMSA攻擊漏洞:跨域攻擊與持久化訪問風險分析

網絡安全研究人員近日披露了Windows Server 2025中委托管理服務賬戶(dMSA,Delegated Managed Service Accounts)存在的"關鍵設計缺陷"。據Semperis公司向The Hacker News提供的報告顯示:"該漏洞可能導致高危害攻擊…

解鎖數據分析:從基礎概念到核心指標的全面指南

在數字化時代,數據已成為驅動業務決策的核心力量。無論是運營一款 APP、管理一家便利店,還是優化在線教育課程,理解數據的本質與關鍵指標都至關重要。本文將從數據的基本概念出發,拆解運營全流程中的核心指標,并分享數…

DiffPy-CMI詳細安裝教程

本章教程,主要記錄安裝DiffPy-CMI的具體安裝步驟。 DiffPy-CMI 是一個復雜建模框架,是高度靈活的 Python 模塊庫,專為晶體、納米材料及非晶態材料的納米結構建模而設計。 注意:DiffPy-CMI只支持在Linux和Mac上安裝,Windows上是不支持的。 一、準備工作 需要準備一臺Linux或…

中國各省市縣坡度數據(Tif/Excel)

數據簡介 昨天我們分享了中國120m精度的DEM數據(見前文),今天我們根據該數據計算中國的坡度數據,并根據中國省市縣行政區劃數據將其統計各省市縣坡度的最大、最小以及平均值,方便大家研究使用。 基于中國120米精度DEM生成的坡度數據&#xff…

09-three.js Materials

Three.js Journey — Learn WebGL with Three.jsThe ultimate Three.js course whether you are a beginner or a more advanced developerhttps://threejs-journey.com/?cp3 MeshBasicMaterial 添加3個網格體: /*** Object*/ // MashBasicMaterial const mater…

Netty介紹和基本代碼演示

什么是Netty?Netty是一個基于Java NIO的異步事件驅動的網絡應用框架,主要用于快速開發高性能、高可靠性的網絡服務器和客戶端程序。它簡化了網絡編程的復雜性,提供了豐富的協議支持,被廣泛應用于各種高性能網絡應用中。為什么選擇…

[BrowserOS] Nxtscape瀏覽器核心 | 瀏覽器狀態管理 | 瀏覽器交互層

第三章:Nxtscape瀏覽器核心 歡迎回來! 在前兩章中,我們了解了名為專用AI代理的專家團隊及其管理者AI代理協調器,它們協同解析需求并規劃執行步驟。 但這些代理與協調器實際運行的平臺是什么?答案正是本章的核心——…

時序數據庫處理的時序數據獨特特性解析

時序數據(Time-Series Data)作為大數據時代增長最快的數據類型之一,正在物聯網、金融科技、工業監控等領域產生爆炸式增長。與傳統數據相比,時序數據具有一系列獨特特性,這些特性直接影響了時序數據庫(Time…

uniapp各端通過webview實現互相通信

目前網上,包括官方文檔針對uniapp的webview的內容都是基于vue2的,此文章基于vue3的composition API方式網頁對網頁 由于uniapp中的webview只支持引入h5頁面,不支持互相通信,所以要條件編譯,用iframe導入頁面&#xf…

【Vue】tailwindcss + ant-design-vue + vue-cropper 圖片裁剪功能(解決遇到的坑)

1.安裝 vue-cropper pnpm add vue-cropper1.1.12.使用 vue-cropper <template><div class"user-info-head" click"editCropper()"><img :src"options.img" title"點擊上傳頭像" class"img-circle" /><…

【Java】【力扣】101.對稱二叉樹

思路遞歸大問題&#xff1a;對比 左 右 是否對稱參數 左和右todo 先湊合看代碼/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* …

前端 oidc-client 靜默刷新一直提示:Error: Frame window timed out 問題分析與解決方案

引言 在現代前端開發中&#xff0c;OAuth 2.0 和 OpenID Connect (OIDC) 協議已成為身份驗證和授權的標準解決方案。oidc-client-js 是一個流行的 JavaScript 庫&#xff0c;用于在前端應用中實現 OIDC 協議。其中&#xff0c;靜默刷新&#xff08;Silent Renew&#xff09;是一…

DAY02:【ML 第一彈】KNN算法

一、算法簡介 1.1 算法思想 如果一個樣本在特征空間中的 k 個最相似的樣本中的大多數屬于某一個類別&#xff0c;則該樣本也屬于這個類別。 1.2 樣本相似性 樣本都是屬于一個任務數據集的&#xff0c;樣本距離越近則越相似。 二維平面上點的歐氏距離 二維平面上點 a(x1,y1)a(x_…

wpf 實現窗口點擊關閉按鈕時 ??隱藏?? 而不是真正關閉,并且只有當 ??父窗口關閉時才真正退出?? 、父子窗口順序控制與資源安全釋放?

文章目錄實現方法**方法 &#xff1a;重寫 OnClosing 方法****子窗口&#xff08;SettingView&#xff09;代碼****父窗口&#xff08;MainWindow&#xff09;代碼****關鍵點****適用場景**為什么if (Owner null || !Owner.IsLoaded)能夠判斷父窗口已經關閉**1. Owner null 檢…

硬件設計學習DAY4——電源完整性設計:從概念到實戰

每日更新教程&#xff0c;評論區答疑解惑&#xff0c;小白也能變大神&#xff01;" 目錄 一.電源完整性 1.1電源完整性的核心概念 1.2電源完整性的三個關鍵目標 1.3地彈現象的通俗解釋 1.4總結要點 二.電源分配網絡&#xff08;PDN&#xff09;的作用 電源與GND網絡…

QT跨平臺應用程序開發框架(8)—— 多元素控件

目錄 一&#xff0c;關于多元素控件 二&#xff0c;QListWidget 2.1 主要方法 2.2 實現新增刪除 三&#xff0c;Table Widget 3.1 主要方法 3.2 代碼演示 四&#xff0c;Tree Widget 4.1 主要方法 4.2 代碼演示 一&#xff0c;關于多元素控件 多元素控件就是一個控件里面包含了…

【React Native】環境變量和封裝 fetch

環境變量和封裝fetch 環境變量 一般做開發&#xff0c;都會將接口地址配置到環境變量里。在Expo建的項目里&#xff0c;也可以使用環境變量。 在項目根目錄新建一個.env文件&#xff0c;里面添加上&#xff1a; EXPO_PUBLIC_API_URLhttp://localhost:3000如果你用手機真機等…