虚拟地址空间

首先,一个程序被加载到内存中首先会存在两种属性:静态分配内存和动态分配内存。
静态分配内存:是在程序编译和链接时就确定好的内存。(速度快,不易犯错,例如:全局变量和static变量等)
动态分配内存:是在程序加载、调入、执行测时候分配/回收的内存。

线性空间在linux32位系统上有大约4G的大小,所以我们的虚拟地址空间总共也就是这4G大小。虚拟地址空间可以分为内核空间和用户空间。最高的1G大小内存是内核空间(虚拟地址从0xC0000000~0xFFFFFFFF),内核空间在各进程之间是共享的。下面的3G大小内存是用户内存(虚拟地址从0x00000000~0xBFFFFFFF),用户空间是每个进程独立拥有的,其开头有128M大小内存为系统所特有,我们并不能访问。
其实,大概就是这样一个分布。
这里写图片描述
1.内核空间
内核空间在内存中,是操作系统的一部分,内核空间为内核所留,它不允许应用程序读写该区域或者直接调用内核代码的函数。
2.环境变量和命令行参数
环境变量和命令行参数都是一组字符串,环境变量是操作系统传递给进程的一组字符串信息。命令行参数列表由char**argv指向,字符串个数由int argc指明,它们就是main函数的两个参数,还有一个全局变量char* *envp,它指向环境表(环境字符串的集合)并以NULL空串结尾,只是我们习惯省略这些,所以我们的常写的main函数是main()。
即: int main(int argc,char*argv[],char*envp[])
3.栈
栈,又称为堆栈,由编译器自动分配释放,行为类似于数据结构中的栈,有先进后出的特性。栈的三个用途:
(1)为函数内部的非静态局部变量开辟存储空间。
(2)记录函数调用过程中的相关信息,包括函数返回地址,不适合装入寄存器的函数参数和一些寄存器值的保存。
(3)保存程序的当前状态。
4.堆
堆是由程序员手动完成申请和释放的,像malloc()和new(),如果在程序结束之后程序员没有手动释放,将由系统进行回收释放,当然,这只是以防万一的情况,如果用malloc申请空间,就用free释放,如果用new申请,就用delete释放。其实堆方式并不像数据结构中的堆的实现方式,更像数据结构中的链表的实现方式。堆的特点就是动态分配内存,它是从低地址向高地址申请空间,是不连续的内存区域,可读可写可执行,堆的大小受限于计算机的虚拟内存, 一般在开头的一字节存放的是堆的大小。
在malloc底层的实现中,当我们申请128K以下的内存是用brk来申请由malloc来管理,所以当我们free之后,它并不会把内存交回给内核而是malloc,所以我们还可以通过指针访问到这块内存。这样效率就会比较高。
我们可以看到上面的图堆的部分有一部分叫做共享库存储映射区,它就是如动态库、共享内存等映射物理空间的内存,一般是 mmap 函数所分配的虚拟地址空间。
补充:new和malloc的区别
(1)new是c++的一个运算符,而malloc是数据库函数。
(2)它们都是用来动态开辟内存的,new的底层实现是malloc,也就是说new底层可以调用malloc,但是malloc底层不能调用new。
(3)new有三种用法,而malloc只有一种用法。
(4)new开辟内存失败会抛出异常,malloc则会返回一个void*。
(5)new有重载而malloc没有。
(6)new没有提供重载,malloc有,即realloc函数。
(7)new开辟内存时不需要指出大小,malloc必须指出。
5. .bss区域
bss段是数据段,里边存放的是未初始化的全局变量和静态变量。
6. .data区域
data段也是数据段,里面只存放初始化的非零静态局部变量和全局变量,静态分配。它的属性是可读可写不可执行。在data段上面有一个rodata段(rodata段的位置在.o文件时去观察它是在.bss段的下方),它的属性是只可读。
data可分为读写(RW)区域和只读(RO)区域。
RW—只读数据段是程序使用的一些不会被更改的数据,因此只需要放置在只读存储器中即可。
RO—已初始化数据是在程序中声明,并且具有初值的变量,这些变量需要占用存储器的空间,在程序执行时它们需要位于可读写的内存区域内,并具有初值,以供程序运行时读写。
7. .text区域
text段y被称为代码段,里边保存的是程序文本(程序执行代码),同时也可能会包含一些常量(如一些字符串常量等),指令指针EIP就是指向代码段,它的权限是刻度可执行不可写。该段内存为静态分配,这些内存同时也是共享的,比如说有多个相同进程存在时,公用一个text段。

猜你喜欢

转载自blog.csdn.net/qq_39110766/article/details/79477167