Linux 上 C 程序的内存布局
在仔细研究这个问题之前,我认为 C 程序在内存中只有代码段,堆和栈三部分构成。前几天面试被问到了这个问题,才发现自己的印象是不完全的。
在本文中通过解析析一个 C 程序中变量和函数的地址来分析 C 程序在内存中的布局。
首先简单介绍一下Linux上C程序的内存分布。

一般情况下从低地址到高地址分布着:
- 程序代码段及只读数据段
- 程序代码,以及字符串常量等都存储在这里
- 可读可写数据段
- 全局变量,静态变量存储在这里
- 数据堆
- 程序中动态分配的内存在这一块
- 共享库
- 程序加载的共享库加载在这个地方
- 数据栈
- 局部变量,函数参数,函数返回地址等存储在这里
- 内核地址
- 操作系统内核内存空间
C语言代码如下(var_memory.c)
#include <stdio.h>
#include <stdlib.h> #include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <argp.h> int global = ;
static int static_global = ; int main()
{
char *string_literal = "hello";
static int static_local = ;
char local_array[] = {'a', 'b', 'c'};
int *malloced = (int *)malloc(*sizeof(int)); pid_t pid = getpid();
printf("pid: %ld\n", (long)pid); // string_literaling literal and function in this module are loaded
// into readonly and excutable segment
printf("%.8p: addr of main\n", &main);
printf("%.8p: addr of local string_literal literal\n", string_literal);
puts(""); // static and global variables are allocated in data segment
printf("%.8p: addr of global int\n", &global);
printf("%.8p: addr of global static int\n", &static_global);
printf("%.8p: addr of local static int\n", &static_local);
puts(""); // allocated in heap
printf("%.8p: addr of local malloc\n", malloced);
puts(""); // errno is from a library
printf("%.8p: addr of errno\n", &errno);
puts(""); // printf is from a library
printf("%.8p: addr of printf\n", &printf);
puts(""); printf("%.8p: addr of argp_program_verstatic_localon_hook\n", & argp_program_version_hook);
puts(""); // local variable in stack
printf("%.8p: addr of local pid\n", &pid);
printf("%.8p: addr of local array\n", local_array);
puts(""); scanf("%s", local_array);
return ;
}
在linux命令行
make var_memory.c
生成var_memory可执行文件,运行
./var_memory
输出如下:
pid:
0x004b26dd: addr of main
0x004b29d0: addr of local string_literal literal 0x004b4008: addr of global int
0x004b400c: addr of global static int
0x004b4010: addr of local static int 0x00d30160: addr of local malloc 0xb7db86b4: addr of errno 0xb7e0b1c0: addr of printf 0xb7f8f798: addr of argp_program_verstatic_localon_hook 0xbf85518c: addr of local pid
0xbf855198: addr of local array
打开另外一个终端窗口,根据上面输出的pid,运行命令
pmap 4760 # 进程id以上面输出为准
输出如下
: ./var_memory
004b2000 4K r-x-- var_memory
004b3000 4K r---- var_memory
004b4000 4K rw--- var_memory
00d30000 136K rw--- [ anon ]
b7db8000 8K rw--- [ anon ]
b7dba000 1852K r-x-- libc-2.26.so
b7f89000 4K ----- libc-2.26.so
b7f8a000 8K r---- libc-2.26.so
b7f8c000 4K rw--- libc-2.26.so
b7f8d000 12K rw--- [ anon ]
b7fbb000 8K rw--- [ anon ]
b7fbd000 12K r---- [ anon ]
b7fc0000 8K r-x-- [ anon ]
b7fc2000 148K r-x-- ld-2.26.so
b7fe7000 4K r---- ld-2.26.so
b7fe8000 4K rw--- ld-2.26.so
bf836000 132K rw--- [ stack ]
total 2352K
从运行C语言程序与pmap的输出可以看出。
- main函数(0x004b26dd)和字符串常量(0x004b29d0)被分配在了内存区域
- 004b2000 4K r-x-- var_memory,其中rx代表只读和可执行
- 全局变量global(0x004b4008),全局静态变量 static_global(0x004b400c),局部静态变量(0x004b4010)被分配在了数据段
- 004b4000 4K rw--- var_memory,其中rw代表可以读和写
- 使用malloc分配的空间(0x00d30160)处在堆(heap)里
- 00d30000 136K rw--- [ anon ]
- 共享库提供的全局变量errno(0xb7db86b4),被分配在共享库数据段里
- b7db8000 8K rw--- [ anon ]
- 共享库提供的函数printf(0xb7e0b1c0),被分配在共享库代码段里
- b7dba000 1852K r-x-- libc-2.26.so
- 局部变量(0xbf85518c,0xbf855198)被分配在了栈上
- bf836000 132K rw--- [ stack ]
希望这篇文章,对同样困惑于C程序在内存中布局的你有所帮助。
Linux 上 C 程序的内存布局的更多相关文章
- Linux下C程序的内存布局
参考下列书籍中的对应章节: <Linux高级程序设计(第3版)>第3章Linux进程存储管理.相关视频:一.二. <C专家编程>第6章 运动的诗章:运行时数据结构. <U ...
- Anatomy of a Program in Memory.剖析程序的内存布局
原文标题:Anatomy of a Program in Memory 原文地址:http://duartes.org/gustavo/blog/ [注:本人水平有限,只好挑一些国外高手的精彩文章翻译 ...
- linux上应用程序的执行机制
linux上应用程序的执行机制 执行文件是如何在shell中被"执行"的.本文中尽可能少用一些源码,免得太过于无 聊,主要讲清这个过程,感兴趣的同学可以去查看相应的源码了解更多的信 ...
- C语言程序的内存布局
C语言程序的内存布局 一:C语言程序的存储区域 C语言编写的程序经过编绎-链接后,将形成一个统一的文件,它由几个部分组成,在程序运行时又会产生几个其他部分,各个部分代表了不同的存储区域: 1.代码段( ...
- Linux下C程序的内存映像
2.Linux下C程序的内存映像 2.1. 代码段.只读数据段(1)对应着程序中的代码(函数),代码段在Linux中又叫文本段(.text)(2)只读数据段就是在程序运行期间只能读不能写的数据,con ...
- Linux上java程序的jar包启动通用脚本(稳定用过)
Linux上java程序的jar包启动通用脚本如下: #! /bin/sh export LANG="zh_CN.GBK" SERVICE_NAME=` .sh` SCRIPT_N ...
- ESP32应用程序的内存布局
应用程序内存布局 ESP32芯片具有灵活的内存映射功能.本节介绍ESP-IDF在默认情况下如何使用这些功能. ESP-IDF中的应用程序代码可以放置在以下内存区域之一中. IRAM(指令RAM) ES ...
- Linux 上如何清除 RAM 内存高速缓存,缓存和交换空间
像任何其他的操作系统一样,GNU / Linux已经有效地实施了内存管理甚至更多.但是,如果有任何进程正在蚕食你的内存,你要清除它,Linux提供了一个方法来刷新或清除RAM缓存. 在Linux中如何 ...
- 分析Linux上的程序依赖
ldd [path_to_exe] ldd通过调用动态链接器来获取可执行程序的依赖库,但是并不推荐在未知的可执行程序上执行业ldd来获取其依赖库,因为部分版本的ldd会直接通过调用该可执行程序来获取其 ...
随机推荐
- jquery 循环获取checkBox的值,以及对复选框选中,取消,操作按钮
法一:jquery 循环获取选中checkBox框的值 function checkeds() { $("input:checkbox").each(function(index) ...
- 查看 Apache并发请求数及其TCP连接状态【转】
查看 Apache并发请求数及其TCP连接状态 (2011-06-27 15:08:36) 服务器上的一些统计数据: 1)统计80端口连接数netstat -nat|grep -i "80& ...
- IDEA新建Maven项目
Maven是什么? 当我们在开发一个项目的时候,不可避免地会使用到第三方的类库,而它们又可能依赖着另外的Jar包,又得引入其他Jar包,而且我们很容易就会引漏掉~然后就会报错,有时候报的错会让我们花掉 ...
- Android Camera2采集摄像头原始数据并手动预览
Android Camera2采集摄像头原始数据并手动预览 最近研究了一下android摄像头开发相关的技术,也看了Google提供的Camera2Basic调用示例,以及网上一部分代码,但都是在Te ...
- 浅谈GlusterFS
GlusterFS 标签(linux): 分布式文件系统 笔者Q:972581034 交流群:605799367.有任何疑问可与笔者或加群交流 图片来自于官网:http://gluster.readt ...
- 企业级Docker私有仓库之Harbor部署(http)
部署环境 Centos7.3 x64 docker-ce-17.06.0 docker-compose-1.15.0 Python-2.7.5(系统默认) Docker及Docker-compose安 ...
- Nginx+Keepalived负载均衡高可用
Nginx+Keepalived负载均衡高可用方案: Nginx 使用平台:unix.linux.windows. 功能: A.www web服务 http 80 b.负载均衡(方向代理proxy) ...
- linux tar 压缩解压命令
tar命令: -c 压缩-x 解压缩-t 不解压的情况下查看文件内容-r 向压缩文件追加文件-u 更新压缩文件 以上参数必须和'-f'参数连用,且'-f'必须为最后一个参数,后接文档名 -z 对应gz ...
- js结合方式:
1. 在页面中使用script标签,在标签中书写js代码.<head><script type="text/javascript"> alert(&q ...
- python--关于赋值与深浅拷贝的认识
作为一个自学python的小白,平时用到深浅拷贝的机会很少,因此对其也是一知半解.但是,作为一个立志成为后端工程狮的男人,眼里揉不了沙子,于是专门花时间补了补课,在此记录一下学习心得. 在讲深浅 ...