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

C 程序進程記憶體結構深度解析

     編輯:關於C語言

進程虛擬地址空間佈局

每個進程都在獨立的虛擬地址空間中運行。在 32 位系統中,4 GB 的地址空間被劃分為用戶空間(0 ~ 3 GB,即 0x00000000 ~ 0xBFFFFFFF)和內核空間(3 GB ~ 4 GB,即 0xC0000000 ~ 0xFFFFFFFF)。用戶空間進一步包含三個核心數據段:代碼段、數據段、堆棧段。

代碼段

存放可執行文件的機器指令與程序定義的常量。為了防止運行時被意外修改,代碼段屬性為只讀。多個進程若執行同一程序,可共享同一代碼段副本,節省物理內存。

數據段

緊接代碼段之後,分為初始化數據段與未初始化數據段(BSS 段)。前者存放已賦初值的全局變量與靜態變量;後者存放未顯式初始化的全局變量,程序啟動時由內核自動清零。

堆棧段

  • 堆:用於動態內存分配(如 malloc/new),釋放時歸還(free/delete)。堆向高地址增長,大小僅受虛擬地址空間限制。
  • 棧:存放函數調用的臨時變量、參數、返回地址等。棧向低地址增長,先進後出(LIFO),大小受作業系統限制(通常默認 8 MB),適用於小塊、短生命週期數據。

示例代碼與運行結果分析

以下程序演示如何通過打印關鍵符號地址來觀察各段分佈:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int etext, edata, end;          // 鏈接器定義的段邊界符號
char *g_pstr = "Global string\n"; // 初始化全局變量 → 數據段
char g_buffer[20];               // 未初始化全局變量 → BSS 段

inline void disp_addr(char *name, int addr) {
    printf("Name: %-20s Address: %08x\n", name, addr);
}

void disp_var(char *p) {
    char *buffer1;
    disp_addr("buffer1 address:", (int)&buffer1); // 局部變量 → 棧
    buffer1 = (char*)malloc(strlen(p) + 1);       // 動態分配 → 堆
    strcpy(buffer1, p);
    printf("buffer1: %s\n", buffer1);
    free(buffer1);
}

int main() {
    int i = 0;
    printf("Addr etext: %p\n", &etext);   // 代碼段結束
    printf("Addr edata: %p\n", &edata);   // 初始化數據段結束
    printf("Addr end:   %p\n", &end);     // BSS 段結束

    disp_addr("function main()", (int)main);
    disp_addr("function disp_var():", (int)disp_var);
    disp_addr("g_pstr address:", (int)&g_pstr);
    disp_addr("g_buffer address:", (int)&g_buffer);
    disp_addr("i address:", (int)&i);

    disp_var(g_pstr);
    return 0;
}

典型輸出(32 位 Linux)

Addr etext: 0x08049954
Addr edata: 0x08049958
Addr end:   0x08049950
Name: function main()        Address: 0804850c
Name: function disp_var():   Address: 080484a7
Name: g_pstr address:        Address: 08049930
Name: g_buffer address:      Address: 0804993c
Name: i address:             Address: bf8583ec
Name: buffer1 address:       Address: bf8583bc
buffer1: Global string

地址解讀

  • etext、edata、end 依次標記代碼段、初始化數據段、BSS 段的結束邊界。
  • 函數地址(main、disp_var)落在代碼段低地址區(0x08048xxx)。
  • 全局變量 g_pstr、g_buffer 位於數據段/BSS 區(0x08049xxx)。
  • 局部變量 i、buffer1 位於棧區高地址(0xbf8xxxxx),且 buffer1 的值指向堆區分配的內存。

核心總結

  • 代碼段只讀可共享;數據段/BSS 隔離於各進程。
  • 堆由程序員手動管理,靈活但易產生碎片與洩漏;棧由編譯器自動管理,速度快但容量有限。
  • 理解段分佈有助於定位緩衝區溢出、內存洩漏、棧溢出等經典問題。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved