linux 堆、栈、全局变量存放

在学习《深入理解计算机系统》中链接这一章中,数据讲一个可执行文件包含多个段。在Linux系统中代码段总是从0x08048000处开始,数据段在接下来的4KB对齐的地址处,运行时堆在接下来的读写段之后的第一个4KB对齐的地址处,并通过调用malloc库网上增长,开始于地址0x40000000处的段是为共享库保留的,用户栈总是从地址0xbfffffff处开始,并向下增长,从栈的上部开始于地址0xc0000000处的段是为操作系统驻留存储器部分的代码和数据保留的。如下图:


下面通过代码来测试:

#include<stdio.h>
int a1=0;
static int sa=0;
int a2=0;
int b;
int main()
{
	int c1=1;
	int c2;
	int *d=(int *)malloc(sizeof(int)*10);
	int *e=(int *)malloc(sizeof(int)*10);
	static int f=0;
	if(d==NULL)
	{
		printf("malloc error");
		return -1;
	}
	printf("a1:%p\n",&a1);
	printf("sa:%p\n",&sa);
	printf("a2:%p\n",&a2);
	printf("b:%p\n",&b);
	printf("c1:%p\n",&c1);
	printf("c2:%p\n",&c2);
	printf("d:%p\n",&d);
	printf("*d:%p\n",d);
	printf("e:%p\n",&e);
	printf("*e:%p\n",e);
	printf("f:%p\n",&f);
	printf("%p\n",&"123");
	free(d);
	return 0;
}
运行结果如下:

分析如下:

a1,a2,sa,f是按序存放,且全局共有非静态变量和静态变量是分开存放的,紧接着存放的是全局非初始化变量b,由于是int型,故地址相差4.

c1,c2,d,e这几个变量存储在用户栈空间。主要区分d、e和d、e申请内存之间的区别。

*d,*e 代表申请的内存,地址是增大方向,即地址是向上增长的,为堆中申请的数据。

“123”为常量,地址0x80486da应该在只读段的范围内,属于rodate数据。

故可知:C程序中,全局变量和静态变量存储在读写段,常量存储在制度段,动态申请的内容是在堆上,局部变量在运行时栈中。


<think>我们正在讨论全局变量在多线程环境中的存储位置。根据引用[1]和引用[2]: 全局变量存储在全局区(静态区),既不在中也不在中。 引用[1]明确说明:“全局变量既不在中也不在中,而是在全局区(静态区)”。 引用[2]也指出:“全局区(静态区)(static):全局变量静态变量是存储在一起的”。 因此,对于多线程环境,全局变量仍然是存储在全局区(静态区)。这个区域在程序启动时分配,在程序结束时由系统释放。 但是,在多线程环境下,多个线程都可以访问全局变量,因此需要特别注意同步问题(例如使用互斥锁)。 回答用户的问题:全局变量既不存储在线程中,也不存储在系统中,而是存储在全局区(静态区)。 下面我将详细说明:</think>### 全局变量在多线程环境中的存储位置分析 根据引用内容,**全局变量既不存储在线程中,也不存储在系统中**,而是位于独立的**全局区(静态区)**。具体存储机制如下: #### 一、存储位置的本质 1. **全局区(静态区)特性** - 全局变量静态变量共同存储在**数据段(Data Segment)** 中,分为两个子区域: - **初始化数据段**:存放已初始化的全局变量静态变量[^1][^2][^4] $$ \text{示例:} \quad \text{int global\_init = 10;} $$ - **未初始化数据段(BSS段)**:存放未初始化的全局变量静态变量,程序加载时自动清零[^1][^2] $$ \text{示例:} \quad \text{int global\_uninit;} $$ 2. **与线程/的对比** | 存储区域 | 生命周期 | 存储内容 | 多线程访问特性 | |----------------|------------------------|------------------------|----------------------| | **全局区** | 程序启动到结束 | 全局变量静态变量 | 所有线程共享 | | **线程** | 线程创建到销毁 | 局部变量、函数调用链 | 线程私有(不共享) | | **系统** | 手动分配/释放 | 动态分配对象(malloc等) | 需显式共享 | #### 二、多线程环境下的关键特性 1. **共享访问机制** - 全局变量被**所有线程共享**,任何线程都可直接读写[^2] - 需通过同步机制(如互斥锁)避免竞态条件: ```c pthread_mutex_t lock; // 全局互斥锁 int shared_counter; // 共享全局变量 void* thread_func(void* arg) { pthread_mutex_lock(&lock); shared_counter++; // 安全访问 pthread_mutex_unlock(&lock); return NULL; } ``` 2. **内存映射原理** - 程序加载时,操作系统在**虚拟地址空间**固定位置分配全局区[^4] - 所有线程的页表均映射到同一物理内存区域: ``` 线程1虚拟地址空间 ──────┐ ├─→ 物理内存全局区 线程2虚拟地址空间 ──────┘ ``` 3. **与线程私有存储对比** | 特性 | 全局变量 | 线程局部变量(`__thread`) | |--------------|---------------------------|--------------------------| | **存储位置** | 全局区(所有线程可见) | 线程(每个线程独立副本) | | **访问速度** | 直接内存访问 | 需通过线程ID偏移寻址 | | **适用场景** | 跨线程数据共享 | 线程私有状态(如errno) | #### 三、典型内存布局验证 以Linux x86_64进程为例: ```text 高地址 0x7fffffffffff ┌─────────────┐ │ (stack) │ ← 线程(每个线程独立) ├─────────────┤ │ ↓ │ │ ↑ │ ├─────────────┤ │ (heap) │ ← malloc/new分配区域 ├─────────────┤ │ BSS段 │ ← 未初始化全局变量 ├─────────────┤ 0x601000 │ Data段 │ ← 已初始化全局变量 ├─────────────┤ 0x400000 │ Text段 │ ← 程序代码 低地址 ``` > 注:所有线程共享Data段和BSS段,但拥有独立的空间[^2][^4] #### 四、实践建议 1. **线程安全设计** - 避免无保护的全局变量写入,优先使用原子操作或锁 - 只读全局变量(如`const int MAX_SIZE=1024;`)天然线程安全 2. **内存优化** - 频繁访问的全局数据应对齐缓存行(如`alignas(64)`) - 将关联性强的全局变量放在相同缓存行减少miss率 3. **调试技巧** - 使用`nm`命令查看全局变量地址: ```bash nm ./program | grep ' B ' # 查看BSS段全局变量 nm ./program | grep ' D ' # 查看Data段全局变量 ``` > 💡 **关键结论**:全局变量存储在独立于/的全局区,多线程环境下所有线程共享同一内存副本,必须通过同步机制保证数据一致性[^1][^2][^4]。 --- **相关问题** 1. 如何设计线程安全的全局变量访问机制? 2. 多线程程序中全局变量和线程局部存储(`thread_local`)的性能差异有多大? 3. 常量全局变量(`const`)是否也需要加锁保护? 4. C++中静态局部变量与全局变量在多线程环境有何区别? 5. 如何检测多线程程序中的全局变量内存冲突?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值