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

C 語言細節探討(22):函數返回指針的懸空指針風險與進程內存分配上限測試

     編輯:關於C語言

懸空指針與內存分配極限

本文探討兩個經典 C 語言細節:函數返回局部數組指針導致的懸空指針,以及測試進程可分配的最大堆內存。

懸空指針陷阱

// ❌ 錯誤:返回局部數組指針
char* bad_favorite_fruit() {
    char fruit[] = "apple"; // 棧上分配,函數返回時銷毀
    return fruit; // 返回已失效內存地址 → 懸空指針
}

// ✅ 正確 1:static 延長生命周期至程序結束
char* good_favorite_fruit_static() {
    static char fruit[] = "apple"; // 數據段分配,全程有效
    return fruit;
}

// ✅ 正確 2:動態分配 (調用者負責 free)
char* good_favorite_fruit_malloc() {
    char *fruit = malloc(6); // 堆上分配
    if (fruit) strcpy(fruit, "apple");
    return fruit;
}

// ✅ 正確 3:調用者提供緩衝區
void good_favorite_fruit_buf(char *buf, size_t size) {
    if (size >= 6) strcpy(buf, "apple");
}

原理:局部變量 (非 static) 分配在**棧**上,函數返回時棧幀彈出,內存被標記為可復用,隨時可能被覆蓋。返回其地址即為懸空指針,解引用屬未定義行為 (UB)。

測試進程最大可分配內存

#include 
#include 

int main() {
    size_t total_kb = 0;
    // 每次申請 1KB (1024 字節)
    while (malloc(1 << 10) != NULL) {
        ++total_kb;
    }
    printf("Allocated %zu KB total\n", total_kb);
    // 注意:分配的內存未 free,程序退出時 OS 自動回收
    return 0;
}

運行結果解讀

  • 輸出示例:Allocated 2048000 KB total (約 2GB,32 位進程典型值)。
  • 64 位進程受限於虛擬地址空間大小 (通常 128TB+),物理內存+交換分區才是真正上限。
  • malloc 失敗返回 NULL,可能原因:虛擬地址空間耗盡、內存碎片化、ulimit -v 限制、過度提交策略。

補充:內存分配相關限制

工程建議

  1. **永不** 返回棧上局部數組/結構體指針。靜態分析工具 (Clang Static Analyzer, Coverity) 可自動檢測。
  2. 動態分配內存的函數**文檔必須標註** 所有權轉移 (誰負責 free)。
  3. 大塊內存分配前檢查 malloc 返回值,失敗時優雅降級而非崩潰。
  4. 長期運行服務監控內存使用量,防止洩漏導致 OOM。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
限制來源查看/設置命令說明
進程虛擬地址空間架構決定 (32位 4GB, 64位 256TB+)理論上限
RLIMIT_AS (虛擬內存)ulimit -v / setrlimit管理員可限制進程最大虛擬內存
RLIMIT_DATA (數據段/堆)ulimit -d限制堆增長大小
過度提交/proc/sys/vm/overcommit_memoryLinux 默認允許過度提交,malloc 可能「成功」但實際用時 OOM Killer 殺進程