虚拟内存空间

一.什么是虚拟内存空间,它是用来做什么的?

它是一个为了多个进程在执行时访问相同地址的变量时不冲突而引申出来的一个可以映射到物理内存中的物理地址的抽象概念。

二.为什么要存在这么一个虚拟空间而不直接使用物理内存地址去访问内存而是选择用虚拟内存地址去访问内存呢?

通过使用虚拟内存地址,操作系统可以为每个应用程序提供一个独立的地址空间,从而保护应用程序之间的内存不受彼此的影响。

和平的世界

三.Linux 进程虚拟内存空间

每一个虚拟内存空间都含有内核空间和用户态空间两部分。32 位位机器的 Linux 系统中的虚拟内存空间和 64 位的虚拟内存空间也有很大的区别。32 位虚拟内存空间长成这个样子。

代码段:一段写好的程序代码被转换为机器码,作为二进制文件储存在磁盘中,当 CPU 执行二进制文件之前会将这段机器码加载进内存存放这些机器码的虚拟内存空间叫做代码段。

数据段和 bss 段:都是用于储存代码受编译后储存在二进制文件中的全局变量和静态变量的段,在程序运行之前,这些变量也会被加载进内存中供程序访问。区别在于指定了初始值的变量放在数据段,未指定的变量存在 bss 段上后初始化为 0。

堆:在程序运行时是可以动态进行内存分配的,用时可分配任意大小的内存块,不用时可以将其释放。分配和释放可以通过调用相关的堆内存管理函数,如 malloc()、calloc()、realloc()和 free() 等来实现。

文件映射与匿名映射区:在我们运行程序时需要用到动态链接库。动态链接库也有自己的对应的代码段,数据段,BSS 段,也需要一起被加载进内存中。还有用于内存文件映射的系统调用 mmap,其作用为将文件与内存进行映射,那么映射的这块内存(虚拟内存)也需要在虚拟地址空间中有一块区域存储。好像是在虚拟内存空间中又开辟了一个虚拟内存空间。而这些储存区域就是文件映射与匿名映射区。

然后这里引入了一个概念就是什么是动态链接,它存在的意义是什么,它和静态链接又有什么区别呢?

在动态链接时,程序会在运行时通过动态链接库提供的符号表来查找需要用的函数和变量,然后将这些函数和变量链接到程序中。动态链接库中的代码和数据可以被多个程序共享,从而减少了程序的内存占用和启动时间。静态链接是将库文件的代码和数据全部复制到可执行文件中,这样,可执行文件就包含了所需要的全部代码和数据,可以在任何计算机上运行,但是会导致可执行文件的体积较大,从而降低了空间利用率和程序的运行效率。而 linux 下的动态链接是通过 PLT&GOT 来实现的。got 表是全局偏移量表,储存的是外部函数的内存真实地址。plt 表叫做程序连接表,用来存储外部函数的入口点,plt 表中含有能够解析地址的函数。效率高在 got 表中的地址是可以改写的,plt 表中的改写不了,当调用函数时,先通过 pIt 表中入口地址找到 got 表中相应的函数地址,跳转到 got 表。如果是第一次调用这个函数是会跳转两次的:第一次从 plt 表中找到相应的 got 表中函数的入口,跳到 got 表,再从 got 表中跳回到 plt 表,目的是已经获得了 got 表中的函数地址,将其带回 plt 表用 plt 表中的解析地址函数进行解析,解析这个函数的地址来获得这个函数的确切地址,获得完后再从 plt 表跳到 got 表,覆盖掉 got表的初始值,再调用函数。如果是第二次执行该函数,则不会再跳转到 plt 表,而是直接跳转执行函数。

栈:用于储存程序运行过程中函数调用的变量与参数。

保留区:0x0000 0000 到 0x0804 8000 这段虚拟内存地址是一段不可访问的保留区,因为在大多数操作系统中,数值比较小的地址通常被认为不是一个合法的地址,这块小地址是不允许访问的。

堆下栈上的区域:用于拓展空间使用。

对比 32 位和 64 位虚拟内存空间的构造,我们发现在用户态空间和内核空间之间有一个地址空洞,除了因为指针寻址大小不同原因而分配的虚拟内存空间不同之外,数据段和代码段之间也有一个不可访问的区域。

为什么会有一个空洞呢?

64 位机器上的指针寻址范围为 2^64,而由于我们根本用不了那么大的内存空间,为了节省内存空间并提高效率,64 位系统只使用了 48 位来描述虚拟内存空间,寻址范围为2^48 ,所能表达的虚拟内存空间为 256TB。而没有用到的高 16 位就形成了这个 0x0000 7FFF FFFF F000 - 0xFFFF 8000 0000 0000 的地址空洞,我们把这个空洞叫做 canonical address空洞。 高 16 位全部为 0 ,那么我们就可以判断出这是一个用户空间的虚拟内存地址。高 16位全部为 1,那么我们就可以判断出这是一个内核空间虚拟内存空间。如果某个虚拟地址落在这段 canonical address 空洞区域中,那就是既不在用户空间,也不在内核空间,肯定是非法访问了。无论高 16 位是 1 还是 0 都有低 32 位地址有效。

不可访问区的作用是防止程序在读写数据段的时候越界访问到代码段,这个保护段可以让越界访问行为直接崩溃,防止它继续往下运行。

#虚拟内存空间#
全部评论

相关推荐

投递腾讯等公司7个岗位
点赞 评论 收藏
转发
点赞 1 评论
分享
牛客网
牛客企业服务