虚拟内存

概述

虚拟内存的一个主要任务就是将程序彼此之间隔离,防止不同进程在同一时刻对相同物理内存争夺或干扰。

虚拟内存技术使得不同进程在运行过程中,他所看到是自己独占了当前系统的4G内存(32位CPU)。

#include <iostream>
using namespace std;

int main() {
    int a = 1;
    int *p = &a;
    cout << p << endl;
    return 0;
}

编译运行,在我的电脑(64 位)中,输出的结果是 0x7ffeefbff5c8 ,这里输出的地址叫做虚拟地址。在计算机真实访问内存的时候,并不会直接访问 0x7ffeefbff5c8 这个物理地址,而是先进行一个转换。可假想这个转换有一个函数,叫 virtual2physical(address) ,那么实际访问的内存则是: virtual2physical(0x7ffeefbff5c8) 。

虚拟地址可能是不唯一的,但物理地址一定是唯一的。比如,不同的虚拟地址,可能可以转换成同一个物理地址(这类似一个哈希的过程)。这样,程序员在编写程序时,并不需要考虑内存冲突的问题,因为操作系统会给他分配一片“连续的虚拟内存”(即便他们的物理地址不一定连续)。

虚拟内存的相关结构


 

代码段(text segment)分为文本区和只读区,文本区存储程序机器码,只读区存储字符串常量。

数据段(data segment)存储已初始化的全局变量,属于静态内存分配。

BSS段存储未初始化的全局变量,静态变量,属于静态内存分配。

栈,由编译器自动申请施放。存储函数的参数局部变量。每当一个函数被调用,该函数的返回类型和一些调用的信息被存放在栈中。然后这个被调用的函数在为他的自动变量和临时变量在栈上分配空间。每调用一个函数一个新的栈就会被使用(进栈)。栈区是从高地址位向低地址位增长的,是一块连续的内存区域,最大容量是由系统预先设定好的,申请的栈空间超出这个界限时就会提示栈溢出。用户能从栈中获取的空间是比较小的。

堆,用于动态分配内存,由程序员手动分配和释放。堆是从低地址向高地址增长,采用链式的存储结构,频繁的malloc/free造成内存空间的不连续,产生碎片。当申请堆空间时库函数是按照一定的算法搜索可用的足够大的空间。因此堆的效率要比栈低得多。

注:

  • 上图中的栈的大小因情况而定。Linux下默认大小是10M,window系统下默认栈的大小为1M,都可以改变,linux 通过ulimit -s指令。
  • 堆的话,理论上内存有多大,就可以建多大,32位的程序在64位系统上运行的时候,一个进程的堆大小应该是不可以超过4G的.
  • 静态内存分配的声明周期从程序开始运行到程序结束。
  • 代码段和数据段在编译时已经分配了空间,栈区和堆区是在程序运行时分配。
  • 当发生栈溢出时会覆盖掉周围内存的数据。

虚拟地址与物理地址的关系通过分页机制实现

分页机制的思想是:通过映射,可以使连续的线性地址与物理地址相关联,逻辑上连续的线性地址对应的物理地址可以不连续。

过程:

通过分页机制将虚拟内存大小不等的段拆分成大小相等的页,内存管理单元会通过页将虚拟内存地址映射到物理内存在进行访问。

 

事实上,在每个进程创建加载时,内核只是为进程“创建”了虚拟内存的布局,具体就是初始化进程控制表中内存相关的链表,实际上并不立即就把虚拟内存对应位置的程序数据和代码(比如.text .data段)拷贝到物理内存中,只是建立好虚拟内存和磁盘文件之间的映射就好(叫做存储器映射),等到运行到对应的程序时,才会通过缺页异常,来拷贝数据。还有进程运行过程中,要动态分配内存,比如malloc时,也只是分配了虚拟内存,即为这块虚拟内存对应的页表项做相应设置,当进程真正访问到此数据时,才引发缺页异常。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值