Linux下一个进程在内存里有三部分的数据,就是”代码段”、”堆栈段”和”数据段”。这三个部分是构成一个完整的执行序列的必要的部分。”代码段”,顾名思义,就是存放了程序代码的数据,假如机器中有数个进程运行相同的一个程序,那么它们就可以使用相同的代码段。”堆栈段”存放的就是子程 序的返回地址、子程序的参数以及程序的局部变量和malloc()动态申请内存的地址。而数据段则存放程序的全局变量,静态变量及常量的内存空间。
下图是Linux下进程内存布局:
栈(stack):栈内存由编译器在程序编译阶段完成,进程的栈空间位于进程用户空间的顶部并且是向下增长,每个函数的每次调用都会在栈空间中开辟自己的栈空间,函数参数、局部变量、函数返回地址等都会按照先入者为栈顶的顺序压入函数栈中,函数返回后该函数的栈空间消失,所以函数中返回局部变量的地址都是非法的。
堆(heap):堆内存是在程序执行过程中分配的,用于存放进程运行中被动态分配的的变量,大小并不固定,堆位于非初始化数据段和栈之间,并且使用过程中是向栈空间靠近的。当进程调用 malloc 等函数分配内存时,新分配的内存并不是该函数的栈帧中,而是被动态添加到堆上,此时堆就向高地址扩张;当利用 free 等函数释放内存时,被释放的内存从堆中被踢出,堆就会缩减。因为动态分配的内存并不在函数栈帧中,所以即使函数返回这段内存也是不会消失。
非初始化数据段(.bss):通常将此段称为 bss 段,用来存放未初始化的全局变量和 static 静态变量。并且在程序开始执行之前,就是在 main()之前,内核会将此段中的数据初始化为 0 或空指针。
初始化数据段(.data):用来保已初始化的全局变量和 static 静态变量。
文本段(.txt):也称代码段这是可执行文件中由 CPU 执行的机器指令部分。正文段常常是只读的,以防止程序由于意外而修改其自身的执行。
Linux 内存管理的基本思想就是只有在真正访问一个地址的时候才建立这个地址的物理映射,Linux C/C++语言的分配方式共有3 种方式。
(1)从静态存储区域分配:就是数据段的内存分配,这段内存在程序编译阶段就已经分配好,在程序的整个运行期间都存在,
例如全局变量,static 变量。
(2)在栈上创建:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是系统栈中分配的内存容量有限,比如大额数组就会把栈空间撑爆导致段错误。
(3)从堆上分配:亦称动态内存分配。程序在运行的时候用 malloc 或 new 申请任意多少的内存,程序员自己负责在何时用free 或 delete 释放内存。此 区域内存分配称之为动态内存分配。动态内存的生存期由我们决定,使用非常灵活,但问题也最多,比如指向某个内存块的指针取值发生了变化又没有其他指针指向 这块内存,这块内存就无法访问,发生内存泄露。
malloc()函数
int *p;
p = (int *)malloc( sizeof(int) );
malloc分配的内存大小至少为size参数所指定的字节数
malloc的返回值是一个指针,指向一段可用内存的起始地址
多次调用malloc所分配的地址不能有重叠部分,除非某次malloc所分配的地址被释放掉
malloc应该尽快完成内存分配并返回
实现malloc时应同时实现内存大小调整和内存释放函数(realloc和free)
#include <stdio.h>
#include <stdlib.h>
int g_var1; // g_var1是未初始化的全局变量,存放在数据段的BSS区,其值默认为0;
int g_var2=20; // g_var1是初始化了的全局变量,存放在数据段的DATA区,其值为初始化值20;
int main(int argc, char **argv) //argv里存放的是命令行参数,他存放在命令行参数区
{
static int s_var1; // s_var1是未初始化的静态变量,存放在数据段 的BSS区,其值默认为0;
static int s_var2=10; // g_var1是初始化了的静态变量,存放在数据段的DATA区,其值为初始化值10;
char *str="Hello"; // str是初始化了的局部变量,存放在栈(STACK)中,其值是"Hello"这个字符串常量存放
在DATA段里RODATA区中的地址
char *ptr; // ptr是未初始化了的局部变量,存放在栈(STACK)中;其值为随机 值,这时候的ptr称 为“野指针(为初始化的指针)”
ptr = malloc(100); // malloc()会从堆(HEAP)中分配100个字节的内存空间,并将该内存空间的首地址返回给ptr存 放;
printf("[cmd args]: argv address: %p\n", argv);
printf("\n");
printf("[ Stack]: str address: %p\n", &str);
printf("[ Stack]: ptr address: %p\n", &ptr);
printf("\n");
printf("[ Heap ]: malloc address: %p\n", ptr);
printf("\n");
printf("[ bss ]: s_var1 address: %p value: %d\n", &s_var1, g_var1);
printf("[ bss ]: g_var1 address: %p value: %d\n", &g_var1, g_var1);
printf("[ data ]: g_var2 address: %p value: %d\n", &g_var2, g_var2);
printf("[ data ]: s_var2 address: %p value: %d\n", &s_var2, s_var2);
printf("[rodata]: \"%s\" address: %p \n", str, str);
printf("\n");
printf("[ text ]: main() address: %p\n", main);
printf("\n");
free(ptr);
return 0;
}