首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C/C++ 記憶體模型深度解析:虛擬記憶體、堆疊/堆分佈、常見 Bug 與最佳實踐

     編輯:關於C

進程虛擬記憶體佈局(32 位元)


0xFFFFFFFF ┌─────────────────────┐
           │   核心空間 (2GB)    │  0x80000000 - 0xFFFFFFFF
           │  (共享映射、驅動)   │
0x80000000 ├─────────────────────┤
           │   用戶空間 (2GB)    │  0x00000000 - 0x7FFFFFFF
           │  ┌───────────────┐  │
           │  │ 基棧          │  │  靜態儲存區:程式碼段、全域/靜態變數、常量
           │  │ (靜態儲存區)  │  │
           │  ├───────────────┤  │
           │  │ 堆            │  │  動態分配:malloc/new,向上增長
           │  │ (向上增長)    │  │
           │  ├───────────────┤  │
           │  │      ...      │  │
           │  ├───────────────┤  │
           │  │ 浮動棧        │  │  函式呼叫幀、區域變數,向下增長
           │  │ (向下增長)    │  │
0x00000000 └─────────────────────┘

三大記憶體區域詳解

區域別名內容生命週期管理方式
基棧靜態儲存區程式碼段、全域變數、static 變數、const 常量程式啟動~結束編譯器靜態分配
堆動態儲存區malloc/free、new/delete 分配的記憶體手動控制程式員手動管理
浮動棧棧函式參數、區域變數、返回位址、暫存器保存函式進入~返回編譯器自動管理 (幀指鏈)

虛擬記憶體機制

  • 分頁:4KB 頁框,MMU 將虛擬頁映射到物理頁框。
  • 換頁:閒置頁面換出至交換分區/檔案,釋放物理記憶體。
  • 缺頁中斷:存取未駐留頁面觸發,OS 從磁碟讀入並更新頁表。
  • 写時複製 (COW):fork() 時父子共享頁面,寫入時才複製。

經典記憶體 Bug 與對策

Bug 類型成因對策
野指標/懸空指標free 後繼續使用、函式返回區域變數位址free 後置 NULL、嚴禁返回區域變數指標
緩衝區溢位陣列越界寫入、strcpy/strcat 無長度檢查用 strncpy/snprintf、界檢查、編譯器強化 (-fstack-protector)
記憶體洩漏malloc 無對應 free、例外路徑漏釋放RAII (C++)、智慧指標、靜態分析工具
雙重釋放同一指標 free 兩次free 後置 NULL、所有權單一化
釋放非堆記憶體free 靜態/棧記憶體只釋放 malloc/new 分配的記憶體
迭代器失效釋放鏈表節點後繼續用 next先存 next 再 free 當前節點

執行緒參數傳遞陷阱


// 錯誤:傳遞區域變數位址
void start_thread_bad() {
    int arg = 42;
    pthread_create(&tid, NULL, thread_func, &arg);  // arg 在棧上,函數返回即失效
}

// 正確:堆上分配參數結構體
typedef struct { int sock; } ThreadArg;

void start_thread_good(int sock) {
    ThreadArg *arg = malloc(sizeof(ThreadArg));
    arg->sock = sock;
    pthread_create(&tid, NULL, thread_func, arg);
}

void *thread_func(void *p) {
    ThreadArg *arg = p;
    // 使用 arg->sock
    free(arg);  // 執行緒結束前釋放
    return NULL;
}

最佳實踐清單

  1. 指標初始化為 NULL,使用前檢查。
  2. 配對分配/釋放:每個 malloc 對應一個 free,new 對應 delete/delete[]。
  3. 所有權語義明確:誰分配誰釋放,或用智慧指標 (C++11 unique_ptr/shared_ptr)。
  4. 邊界檢查:字串操作用 snprintf、strncpy,陣列存取加斷言。
  5. 工具輔助:AddressSanitizer (-fsanitize=address)、Valgrind、Clang Static Analyzer、Cppcheck。
  6. 避免手動管理複雜資料結構:優先用標準庫容器 (vector, string, list) 或成熟庫。

64 位元擴展

  • 用戶空間擴展至 128TB (x86-64 典型 47 位元),核心空間同樣巨大。
  • 指標 8 位元組,size_t/ptrdiff_t 為 64 位元。
  • 棧預設 8MB (Linux),可調整 (ulimit -s、pthread_attr_setstacksize)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved