搜索
首页运维linux运维详解虚拟内存管理

详解虚拟内存管理

Jun 20, 2017 am 11:23 AM
内存管理虚拟

  现代操作系统普遍采用虚拟内存管理(Virtual Memory Management)机制,这需要处理器中的MMU(Memory Management Unit,内存管理单元)提供支持。首先引入 PA 和 VA 两个概念。

1.PA(Physical Address)---详解虚拟内存管理

  如果处理器没有MMU,或者有MMU但没有启用,CPU执行单元发出的内存地址将直接传到芯片引脚上,被内存芯片(以下称为物理内存,以便与虚拟内存区分)接收,这称为PA(Physical Address,以下简称PA),如下图所示。

详解虚拟内存管理

详解虚拟内存管理

2.VA(Virtual Address)---详解虚拟内存管理

  如果处理器启用了MMU,CPU执行单元发出的内存地址将被MMU截获,从CPU到MMU的地址称为详解虚拟内存管理(Virtual Address,以下简称VA),而MMU将这个地址翻译成另一个地址发到CPU芯片的外部地址引脚上,也就是将VA映射成PA,如下图所示。

详解虚拟内存管理

详解虚拟内存管理

  如果是32位处理器,则内地址总线是32位的,与CPU执行单元相连(图中只是示意性地画了4条地址线),而经过MMU转换之后的外地址总线则不一定是32位的。也就是说,详解虚拟内存管理空间和详解虚拟内存管理空间是独立的,32位处理器的详解虚拟内存管理空间是4GB,而详解虚拟内存管理空间既可以大于也可以小于4GB。

  MMU将VA映射到PA是以页(Page)为单位的,32位处理器的页尺寸通常是4KB。例如,MMU可以通过一个映射项将VA的一页0xb7001000~0xb7001fff映射到PA的一页0x2000~0x2fff,如果CPU执行单元要访问详解虚拟内存管理0xb7001008,则实际访问到的详解虚拟内存管理是0x2008。物理内存中的页称为物理页面或者页帧(Page Frame)。虚拟内存的哪个页面映射到物理内存的哪个页帧是通过页表(Page Table)来描述的,页表保存在物理内存中,MMU会查找页表来确定一个VA应该映射到什么PA。

 

3. 详解虚拟内存管理

详解虚拟内存管理详解虚拟内存管理

 

  x86平台的详解虚拟内存管理空间是0x0000 0000~0xffff ffff,大致上前3GB(0x0000 0000~0xbfff ffff)是用户空间,后1GB(0xc000 0000~0xffff ffff)是内核空间。

   Text Segmest 和 Data Segment

  • Text Segment,包含.text段、.rodata段、.plt段等。是从/bin/bash加载到内存的,访问权限为r-x。

  • Data Segment,包含.data段、.bss段等。也是从/bin/bash加载到内存的,访问权限为rw-。

     堆和栈

  • 堆(heap):堆说白了就是电脑内存中的剩余空间,malloc函数动态分配内存是在这里分配的。在动态分配内存时堆空间是可以向高地址增长的。堆空间的地址上限称为Break,堆空间要向高地址增长就要抬高Break,映射新的虚拟内存页面到物理内存,这是通过系统调用brk实现的,malloc函数也是调用brk向内核请求分配内存的。

  • 栈(stack):栈是一个特定的内存区域,其中高地址的部分保存着进程的环境变量和命令行参数,低地址的部分保存函数栈帧,栈空间是向低地址增长的,但显然没有堆空间那么大的可供增长的余地,因为实际的应用程序动态分配大量内存的并不少见,但是有几十层深的函数调用并且每层调用都有很多局部变量的非常少见。

  如果写程序的时候没有注意好内存的分配问题,在堆和栈这两个地方可能产生以下几种问题:

  1. 内存泄露:如果你在一个函数里通过 malloc 在堆里申请了一块空间,并在栈里声明一个指针变量保存它,那么当该函数结束时,该函数的成员变量将会被释放,包括这个指针变量,那么这块空间也就找不回来了,也就无法得到释放。久而久之,可能造成下面的内存泄露问题。

  2. 栈溢出:如果你放太多数据到栈中(例如大型的结构体和数组),那么就可能会造成“栈溢出”(Stack Overflow)问题,程序也将会终止。为了避免这个问题,在声明这类变量时应使用 malloc 申请堆的空间。

  3. 野指针 和 段错误:如果一个指针所指向的空间已经被释放,此时再试图用该指针访问已经被释放了的空间将会造成“段错误”(Segment Fault)问题。此时指针已经变成野指针,应该及时手动将野指针置空。

4. 虚拟内存管理的作用

  1. 虚拟内存管理可以控制物理内存的访问权限。物理内存本身是不限制访问的,任何地址都可以读写,而操作系统要求不同的页面具有不同的访问权限,这是利用CPU模式和MMU的内存保护机制实现的。

  2. 虚拟内存管理最主要的作用是让每个进程有独立的地址空间。所谓独立的地址空间是指,不同进程中的同一个VA被MMU映射到不同的PA,并且在某一个进程中访问任何地址都不可能访问到另外一个进程的数据,这样使得任何一个进程由于执行错误指令或恶意代码导致的非法内存访问都不会意外改写其它进程的数据,不会影响其它进程的运行,从而保证整个系统的稳定性。另一方面,每个进程都认为自己独占整个详解虚拟内存管理空间,这样链接器和加载器的实现会比较容易,不必考虑各进程的地址范围是否冲突。

详解虚拟内存管理是独立的

详解虚拟内存管理是独立的

  1. VA到PA的映射会给分配和释放内存带来方便,详解虚拟内存管理不连续的几块内存可以映射成详解虚拟内存管理连续的一块内存。比如要用malloc分配一块很大的内存空间,虽然有足够多的空闲物理内存,却没有足够大的连续空闲内存,这时就可以分配多个不连续的物理页面而映射到连续的详解虚拟内存管理范围。

详解虚拟内存管理

详解虚拟内存管理

  1. 一个系统如果同时运行着很多进程,为各进程分配的内存之和可能会大于实际可用的物理内存,虚拟内存管理使得这种情况下各进程仍然能够正常运行。因为各进程分配的只不过是虚拟内存的页面,这些页面的数据可以映射到物理页面,也可以临时保存到磁盘上而不占用物理页面,在磁盘上临时保存虚拟内存页面的可能是一个磁盘分区,也可能是一个磁盘文件,称为交换设备(Swap Device)。当物理内存不够用时,将一些不常用的物理页面中的数据临时保存到交换设备,然后这个物理页面就认为是空闲的了,可以重新分配给进程使用,这个过程称为换出(Page out)。如果进程要用到被换出的页面,就从交换设备再加载回物理内存,这称为换入(Page in)。换出和换入操作统称为详解虚拟内存管理(Paging),因此:

    系统中可分配的内存总量=物理内存的大小 交换设备的大小

如下图所示。第一张图是换出,将物理页面中的数据保存到磁盘,并解除地址映射,释放物理页面。第二张图是换入,从空闲的物理页面中分配一个,将磁盘暂存的页面加载回内存,并建立地址映射。

详解虚拟内存管理

详解虚拟内存管理

5.malloc 和 free

C标准库函数malloc可以在堆空间动态分配内存,它的底层通过brk系统调用向操作系统申请内存。动态分配的内存用完之后可以用free释放,更准确地说是归还给malloc,这样下次调用malloc时这块内存可以再次被分配。

1 #include <stdlib.h>2 void *malloc(size_t size);  //返回值:成功返回所分配内存空间的首地址,出错返回NULL3 void free(void *ptr);</stdlib.h>
 

malloc的参数size表示要分配的字节数,如果分配失败(可能是由于系统内存耗尽)则返回NULL。由于malloc函数不知道用户拿到这块内存要存放什么类型的数据,所以返回通用指针void *,用户程序可以转换成其它类型的指针再访问这块内存。malloc函数保证它返回的指针所指向的地址满足系统的对齐要求,例如在32位平台上返回的指针一定对齐到4字节边界,以保证用户程序把它转换成任何类型的指针都能用。

动态分配的内存用完之后可以用free释放掉,传给free的参数正是先前malloc返回的内存块首地址。

示例

举例如下:

 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 typedef struct { 5     int number; 6     char *msg; 7 } unit_t; 8 int main(void) 9 {10     unit_t *p = malloc(sizeof(unit_t));11     if (p == NULL) {12         printf("out of memory\n");13         exit(1);14     }15     p->number = 3;16     p->msg = malloc(20);17     strcpy(p->msg, "Hello world!");18     printf("number: %d\nmsg: %s\n", p->number, p->msg);19     free(p->msg);20     free(p);21     p = NULL;22     return 0;23 }</string.h></stdlib.h></stdio.h>

 

说明

  • unit_t *p = malloc(sizeof(unit_t));这一句,等号右边是void *类型,等号左边是unit_t *类型,编译器会做隐式类型转换,我们讲过void *类型和任何指针类型之间可以相互隐式转换。

  • 虽然内存耗尽是很不常见的错误,但写程序要规范,malloc之后应该判断是否成功。以后要学习的大部分系统函数都有成功的返回值和失败的返回值,每次调用系统函数都应该判断是否成功。

  • free(p);之后,p所指的内存空间是归还了,但是p的值并没有变,因为从free的函数接口来看根本就没法改变p的值,p现在指向的内存空间已经不属于用户,换句话说,p成了野指针,为避免出现野指针,我们应该在free(p);之后手动置p = NULL;

  • 应该先free(p->msg),再free(p)。如果先free(p),p成了野指针,就不能再通过p->msg访问内存了。

6.内存泄漏

  如果一个程序长年累月运行(例如网络服务器程序),并且在循环或递归中调用malloc分配内存,则必须有free与之配对,分配一次就要释放一次,否则每次循环都分配内存,分配完了又不释放,就会慢慢耗尽系统内存,这种错误称为内存泄漏(Memory Leak)。另外,malloc返回的指针一定要保存好,只有把它传给free才能释放这块内存,如果这个指针丢失了,就没有办法free这块内存了,也会造成内存泄漏。例如:

1 void foo(void)2 {3     char *p = malloc(10);4     ...5 }

  foo函数返回时要释放局部变量p的内存空间,它所指向的内存地址就丢失了,这10个字节也就没法释放了。内存泄漏的Bug很难找到,因为它不会像访问越界一样导致程序运行错误,少量内存泄漏并不影响程序的正确运行,大量的内存泄漏会使系统内存紧缺,导致频繁详解虚拟内存管理,不仅影响当前进程,而且把整个系统都拖得很慢。

  关于malloc和free还有一些特殊情况。malloc(0)这种调用也是合法的,也会返回一个非NULL的指针,这个指针也可以传给free释放,但是不能通过这个指针访问内存。free(NULL)也是合法的,不做任何事情,但是free一个野指针是不合法的,例如先调用malloc返回一个指针p,然后连着调用两次free(p);,则后一次调用会产生运行时错误。

 

以上是详解虚拟内存管理的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
Linux:基本命令和操作Linux:基本命令和操作Apr 24, 2025 am 12:20 AM

Linux中不可或缺的命令包括:1.ls:列出目录内容;2.cd:改变工作目录;3.mkdir:创建新目录;4.rm:删除文件或目录;5.cp:复制文件或目录;6.mv:移动或重命名文件或目录。这些命令通过与内核交互执行操作,帮助用户高效管理文件和系统。

Linux操作:管理文件,目录和权限Linux操作:管理文件,目录和权限Apr 23, 2025 am 12:19 AM

在Linux中,文件和目录管理使用ls、cd、mkdir、rm、cp、mv命令,权限管理使用chmod、chown、chgrp命令。1.文件和目录管理命令如ls-l列出详细信息,mkdir-p递归创建目录。2.权限管理命令如chmod755file设置文件权限,chownuserfile改变文件所有者,chgrpgroupfile改变文件所属组。这些命令基于文件系统结构和用户、组系统,通过系统调用和元数据实现操作和控制。

Linux中的维护模式是什么?解释了Linux中的维护模式是什么?解释了Apr 22, 2025 am 12:06 AM

MaintenancemodeInuxisAspecialBootenvironmentforforcalsystemmaintenancetasks.itallowsadMinistratorStoperFormTaskSlikerSettingPassingPassingPasswords,RepairingFilesystems,andRecoveringFrombootFailuresFailuresFailuresInamInimAlenimalenimalenrenmentrent.ToEnterMainterMainterMaintErmaintErmaintEncemememodeBoode,Interlecttheboo

Linux:深入研究其基本部分Linux:深入研究其基本部分Apr 21, 2025 am 12:03 AM

Linux的核心组件包括内核、文件系统、Shell、用户空间与内核空间、设备驱动程序以及性能优化和最佳实践。1)内核是系统的核心,管理硬件、内存和进程。2)文件系统组织数据,支持多种类型如ext4、Btrfs和XFS。3)Shell是用户与系统交互的命令中心,支持脚本编写。4)用户空间与内核空间分离,确保系统稳定性。5)设备驱动程序连接硬件与操作系统。6)性能优化包括调整系统配置和遵循最佳实践。

Linux体系结构:揭示5个基本组件Linux体系结构:揭示5个基本组件Apr 20, 2025 am 12:04 AM

Linux系统的五个基本组件是:1.内核,2.系统库,3.系统实用程序,4.图形用户界面,5.应用程序。内核管理硬件资源,系统库提供预编译函数,系统实用程序用于系统管理,GUI提供可视化交互,应用程序利用这些组件实现功能。

Linux操作:利用维护模式Linux操作:利用维护模式Apr 19, 2025 am 12:08 AM

Linux的维护模式可以通过GRUB菜单进入,具体步骤为:1)在GRUB菜单中选择内核并按'e'编辑,2)在'linux'行末添加'single'或'1',3)按Ctrl X启动。维护模式提供了一个安全环境,适用于系统修复、重置密码和系统升级等任务。

Linux:如何进入恢复模式(和维护)Linux:如何进入恢复模式(和维护)Apr 18, 2025 am 12:05 AM

进入Linux恢复模式的步骤是:1.重启系统并按特定键进入GRUB菜单;2.选择带有(recoverymode)的选项;3.在恢复模式菜单中选择操作,如fsck或root。恢复模式允许你以单用户模式启动系统,进行文件系统检查和修复、编辑配置文件等操作,帮助解决系统问题。

Linux的基本要素:为初学者解释Linux的基本要素:为初学者解释Apr 17, 2025 am 12:08 AM

Linux的核心组件包括内核、文件系统、Shell和常用工具。1.内核管理硬件资源并提供基本服务。2.文件系统组织和存储数据。3.Shell是用户与系统交互的接口。4.常用工具帮助完成日常任务。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境

Dreamweaver Mac版

Dreamweaver Mac版

视觉化网页开发工具

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

SecLists

SecLists

SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。