C程序內存布局詳解

C程序內存布局詳解

1. 內存布局概述

C程序在內存中分為以下幾個主要區域(從低地址到高地址):

  • 代碼段(.text)
  • 只讀數據段(.rodata)
  • 初始化數據段(.data)
  • 未初始化數據段(.bss)
  • 堆(Heap)
  • 棧(Stack)
  • 內核空間(Kernel space)(用戶程序不可訪問)
    注意:堆和棧之間是未分配的內存空間,兩者相向生長。
    在這里插入圖片描述

2. 各區域詳解

2.1 代碼段(Text Segment)

  • 存儲內容:程序的可執行指令(機器代碼)。
  • 特點:只讀、固定大小。
  • 生命周期:程序整個運行期間。
  • 示例
    int main() {return 0;   // main函數的指令存儲在此
    }
    

2.2 只讀數據段(Read-Only Data Segment)

  • 存儲內容:字符串常量、const修飾的全局變量。
  • 特點:只讀,任何修改操作會導致段錯誤(Segmentation Fault)。
  • 生命周期:程序整個運行期間。
  • 示例
    const int max = 100;   // 存儲于.rodata
    char *str = "hello";   // 字符串字面量"hello"存儲于.rodata
    void foo() {// 錯誤示例:嘗試修改只讀數據// str[0] = 'H';   // 運行時錯誤:段錯誤
    }
    

2.3 初始化數據段(Initialized Data Segment)

  • 存儲內容:已初始化的全局變量和靜態變量(非零初始化)。
  • 特點:可讀寫,程序加載時從可執行文件中讀取初始值。
  • 生命周期:程序整個運行期間。
  • 示例
    int global_init = 42;           // 存儲于.data
    static int static_init = 10;    // 存儲于.data
    int main() {// ...
    }
    

2.4 未初始化數據段(Uninitialized Data Segment / .bss)

  • 存儲內容:未初始化或初始化為0的全局變量和靜態變量。
  • 特點:可讀寫,程序加載時由系統初始化為0。
  • 生命周期:程序整個運行期間。
  • 示例
    int global_uninit;         // 存儲于.bss,初始化為0
    static int static_uninit;  // 存儲于.bss,初始化為0
    int main() {// ...
    }
    

2.5 堆(Heap)

  • 存儲內容:動態分配的內存。
  • 特點
    • 手動管理(通過malloccallocrealloc分配,free釋放)。
    • 從低地址向高地址增長。
    • 分配速度相對較慢。
  • 生命周期:從分配成功到顯式釋放。
  • 示例
    int main() {int *arr = (int*)malloc(10 * sizeof(int));  // 在堆上分配if (arr) {arr[0] = 1;   // 合法訪問free(arr);    // 顯式釋放}return 0;
    }
    

2.6 棧(Stack)

  • 存儲內容
    • 函數調用時的返回地址
    • 函數參數
    • 局部變量(非靜態)
    • 函數調用的上下文
  • 特點
    • 由編譯器自動管理(入棧/出棧)。
    • 從高地址向低地址增長。
    • 分配速度快。
    • 大小有限(Linux默認約8MB,可通過ulimit -s查看)。
  • 生命周期:函數調用期間。
  • 示例
    void func(int param) {   // 參數param在棧上int local_var = 10;  // 局部變量在棧上// ...
    }   // 函數結束時,param和local_var自動釋放
    int main() {func(5);return 0;
    }
    

3. 內存布局圖示

高地址
+-----------------------+
|       內核空間         |
+-----------------------+
|         棧            | <- 由高地址向低地址增長
| (局部變量、函數參數等)  |
+-----------------------+
|          ...          |
+-----------------------+
|         堆            | <- 由低地址向高地址增長
|   (動態分配的內存)     |
+-----------------------+
|         .bss          | (未初始化全局/靜態變量)
+-----------------------+
|         .data         | (已初始化全局/靜態變量)
+-----------------------+
|        .rodata        | (只讀數據)
+-----------------------+
|         .text         | (程序代碼)
低地址

在這里插入圖片描述
在這里插入圖片描述
空洞地址(Hole Address) 通常指虛擬地址空間中未被映射到任何物理內存或存儲介質(如磁盤交換區)的地址范圍。這些地址屬于進程可見的虛擬地址空間,但由于未被操作系統分配或關聯到實際的物理資源,無法被進程正常訪問。

核心特點:
1,未映射性:空洞地址沒有對應的物理內存頁或磁盤塊,操作系統的內存管理單元(MMU)無法將其轉換為物理地址。
2,訪問受限:進程若嘗試讀取或寫入空洞地址,會觸發內存訪問錯誤(如 Linux 中的SIGSEGV信號),導致進程終止(俗稱 “段錯誤”)。
3,存在的合理性:,空洞地址并非 “浪費”,而是操作系統設計中用于隔離內存區域的常見手段。例如:
(1)進程的代碼段、數據段、堆、棧等區域之間通常存在空洞,防止不同區域的越界訪問相互干擾;
(2)32 位系統中,用戶空間與內核空間之間可能保留大量未映射的地址作為隔離帶;
(3)動態內存分配(如malloc)后,堆的增長可能與棧的擴展之間形成臨時空洞。

4. 關鍵注意事項

4.1 靜態局部變量的存儲位置

靜態局部變量雖然作用域在函數內,但存儲在.data.bss段(根據是否初始化):

void counter() {static int count = 0;  // 存儲在.data(因為初始化了)count++;
}

4.2 指針與內存區域

指針變量本身存儲在:

  • 全局指針:.data.bss
  • 靜態指針:.data.bss
  • 局部指針:棧上
  • 動態分配指針:堆上(指針變量在棧,指向的內容在堆)

4.3 常見錯誤

  1. 棧溢出(Stack Overflow)
    void recursion() {int arr[10000];  // 大數組占用棧空間recursion();     // 無限遞歸
    }
    
  2. 堆內存泄漏(Memory Leak)
    void leak() {malloc(100);   // 分配后未釋放,且丟失了指針
    }
    
  3. 野指針(Dangling Pointer)
    int* dang() {int local = 10;return &local;   // 返回局部變量地址(函數結束即失效)
    }
    
  4. 重復釋放(Double Free)
    int *p = malloc(sizeof(int));
    free(p);
    free(p);   // 錯誤:重復釋放
    

5. 驗證內存布局的示例程序

#include <stdio.h>
#include <stdlib.h>
const int const_global = 10;      // .rodata
int init_global = 20;             // .data
int uninit_global;                // .bss
int main() {static int static_init = 30;   // .datastatic int static_uninit;      // .bssint local_var;                 // 棧int *heap_var = malloc(10);    // 堆printf("代碼段(.text):   %p\n", main);printf("只讀段(.rodata): %p\n", &const_global);printf("數據段(.data):   %p (init_global)\n", &init_global);printf("數據段(.data):   %p (static_init)\n", &static_init);printf("BSS段(.bss):     %p (uninit_global)\n", &uninit_global);printf("BSS段(.bss):     %p (static_uninit)\n", &static_uninit);printf("堆(Heap):        %p\n", heap_var);printf("棧(Stack):       %p\n", &local_var);free(heap_var);return 0;
}

運行此程序可以觀察到各變量的地址分布,驗證內存布局。

6. 總結

理解C程序內存布局對于:

  • 避免內存錯誤(泄漏、越界、野指針)
  • 優化程序性能(緩存友好性)
  • 理解程序運行機制
    至關重要。務必掌握各區域的特點及生命周期,并在編程中謹慎處理動態內存和指針。

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

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

相關文章

新手向:Git下載全攻略

Git 的安裝與重要性在現代軟件開發中&#xff0c;版本控制是必不可少的工具&#xff0c;而 Git 是目前最流行的分布式版本控制系統。無論是個人開發者還是大型團隊&#xff0c;Git 都能高效管理代碼變更&#xff0c;確保項目歷史清晰可追溯。安裝 Git 是開發者入門的第一步&…

linux中如何清除history命令

寫在前面 使用ssh遠程連接客戶端連接上linux后操作的命令多了&#xff0c;有時候需要清除對應的歷史命令記錄&#xff0c;可以通過下面幾種方式實現。第一種方法 通過修改.bash_history文件 這是最簡單直接的方法&#xff0c;但是只會影響當前用戶的歷史記錄。執行以下命令即可…

PHP插件開發中的一個錯誤:JSON直接輸出導致網站首頁異常

問題描述 最近在使用步數統計插件&#xff08;WeFootStep&#xff09;時&#xff0c;發現網站首頁完全變成了一段JSON數據&#xff0c;而不是正常的HTML頁面。具體表現為首頁顯示如下內容&#xff1a; {"results":"<li><a href\"https:\/\/blog…

落霞歸雁的思維框架:十大經典思維工具的源頭活水

在當今復雜多變的世界中&#xff0c;思維框架成為了解決問題、優化決策和提升效率的重要工具。提到思維框架&#xff0c;人們往往會想到那些被廣泛認可和應用的十大經典思維工具&#xff1a;金字塔原理、黃金圈法則、5W1H分析法、SWOT分析、SCQA模型、STAR法則、PDCA循環、六頂…

spring Could 高頻面試題

一、基礎概念Spring Cloud 的核心組件有哪些&#xff1f; 答案&#xff1a;Eureka/Nacos&#xff08;服務注冊發現&#xff09;、Ribbon/LoadBalancer&#xff08;負載均衡&#xff09;、Feign/OpenFeign&#xff08;聲明式HTTP客戶端&#xff09;、Hystrix/Sentinel&#xff0…

從零開始的云計算生活——番外6,使用zabbix對中間件監控

目錄 一.網絡設備監控 1、GNS模擬器的使用 創建路由 創建交換機 2.構建網絡 3.添加Cisco路由器的監控 二.中間件監控 1、MySQL數據庫監控 1.1、拷貝自定義的監控腳本到指定目錄 1.2、添加監控用戶 1.3、重啟zabbix-agent服務 1.4、在zabbix-server服務端測試數據 1…

haproxy七層均衡

一.haproxy的安裝和服務信息1.1實驗環境ip實驗設備172.25.254.100haproxy172.25.254.10RS1172.25.254.20RS2172.25.254.111client1.2軟件安裝及配置haproxy主機上配置#下載#進入此文件進行編輯#關閉防火墻RS1主機上配置#下載#生成默認文件#重啟#關閉防火墻RS2主機上配置#下載#生…

分類預測 | MATLAB實現CPO-SVM冠豪豬算法優化支持向量機分類預測

分類預測 | MATLAB實現CPO-SVM冠豪豬算法優化支持向量機分類預測 目錄 分類預測 | MATLAB實現CPO-SVM冠豪豬算法優化支持向量機分類預測 分類效果 基本介紹 算法步驟 參數設定 運行環境 應用場景 程序設計 參考資料 分類效果 基本介紹 該MATLAB代碼實現了基于冠豪豬優化算法(…

【MySQL 數據庫】MySQL基本查詢(第二節)

文章目錄&#x1f4dd;Update&#x1f309; 將孫悟空同學的數學成績變更為 80 分&#x1f309; 將曹孟德同學的數學成績變更為60分&#xff0c;語文成績變更為70分&#x1f309; 將總成績倒數前三的3位同學的數學成績加上30分&#x1f309;將所有同學的語文成績更新為原來的2倍…

Axios 響應攔截器

1.定義&#xff1a;響應攔截器&#xff08;Response Interceptor&#xff09;是一個可以在 axios 接收到服務器響應后&#xff0c;響應數據交給 .then() 處理之前執行的函數。你可以用它來統一處理響應數據&#xff0c;進行錯誤處理&#xff0c;或者對返回的數據做格式化和轉換…

k8s的nodeport和ingress

1.流量轉發圖targerport轉發到實際的容器端口containerPort&#xff08;后端端口&#xff09;nodeportingress2.配置場景總結字段作用對象必填示例值何時配置containerPort容器否80需明確記錄容器端口時&#xff08;推薦&#xff09;targetPortPod是80定義 Service 轉發規則時p…

VLA:自動駕駛的“新大腦”?

&#x1f525; 什么是 VLA&#xff1f;為什么突然火了&#xff1f;在自動駕駛圈子里&#xff0c;最近一個詞特別火&#xff1a;VLA。它不是某個新車的型號&#xff0c;也不是某家公司的新品牌&#xff0c;而是一種全新的智能架構&#xff0c;被稱為“自動駕駛的大腦2.0”。&…

Linux操作系統之線程(八):信號量sem

前言&#xff1a;大家好啊&#xff0c;我們上一篇文章已經講解了關于線程同步的一種辦法&#xff1a;運用條件變量cond。今天&#xff0c;我們就來學習一下線程同步的另外一種方法&#xff0c;信號量&#xff01;&#xff01;信號量呢有System V 信號量與POSIX 信號量&#xff…

【RocketMQ】一分鐘了解RocketMQ

MQ是什么 MQ全稱為Message Queue&#xff0c;即消息隊列 &#xff0c;是一種提供消息隊列服務的中間件&#xff0c;也稱為消息中間件&#xff0c;是一套提供了消息生 產、存儲、消費全過程的軟件系統&#xff0c;遵循FIFO原則。 MQ的好處有哪些 異步解耦 最常見的一個場景是…

01 01 01 第一部分 C++編程知識 C++入門 第一個C++程序

第一部分 C編程知識第一章 C入門 —— 第一個C程序一、第一個C程序代碼展示//寫一個C程序&#xff0c;實現在屏幕上打印 “hello world” #include <iostream> using namespace std; int main() {cout << "hello world" << endl;return 0; }二、…

進制定義與轉換詳解

文章目錄&#x1f4d8; 進制定義與轉換詳解一、進制的含義二、常見進制介紹1. 十進制&#xff08;Decimal&#xff0c;Base-10&#xff09;2. 二進制&#xff08;Binary&#xff0c;Base-2&#xff09;3. 八進制&#xff08;Octal&#xff0c;Base-8&#xff09;4. 十六進制&am…

【安卓筆記】用MVC、MVP、MVVM來實現井字棋案例

0. 環境&#xff1a;電腦&#xff1a;Windows10Android Studio: 2024.3.2編程語言: JavaGradle version&#xff1a;8.11.1Compile Sdk Version&#xff1a;35Java 版本&#xff1a;Java111. 首先、簡單實現井字棋的功能。功能拆解&#xff1a;1. 棋盤為3x32. 點擊棋盤button&a…

【洛谷】單向鏈表、隊列安排、約瑟夫問題(list相關算法題)

文章目錄單向鏈表題目描述題目解析代碼隊列安排題目描述題目解析代碼約瑟夫問題題目描述題目解析代碼單向鏈表 題目描述 題目解析 這道題因為有大量的任意位置插入刪除&#xff0c;所以肯定不能用數組&#xff0c;用鏈表是最合適的&#xff0c;而在算法競賽通常都用靜態鏈表&a…

當人機交互邁向新紀元:腦機接口與AR/VR/MR的狂飆之路

從手機到 “頭盔”&#xff1a;交互終端的變革猜想??在當今數字化時代&#xff0c;智能手機無疑是我們生活中不可或缺的一部分。它集通訊、娛樂、辦公等多種功能于一身&#xff0c;成為了人們與外界交互的主要窗口。然而&#xff0c;隨著科技的飛速發展&#xff0c;智能手機作…

InfluxDB HTTP API 接口調用詳解(二)

實際應用案例演示 1. 數據寫入案例 假設在一個物聯網設備數據采集場景中&#xff0c;有多個傳感器設備持續采集環境的溫度和濕度數據。我們以 Python 語言為例&#xff0c;使用requests庫來調用 InfluxDB 的 Write 接口將數據寫入 InfluxDB。 首先&#xff0c;確保已經安裝了…