虚拟内存:
虚拟内存简介:
1:Windows下面,内存分为虚拟内存,物理内存(逻辑内存),虚拟内存和物理内存是相对应的,操作系统支持多进程运行,物理内存只有一块,需要执行某个程序的时候,就将其从虚拟内存加载到物理内存里面去,CPU最终访问的是物理内存,否则速度会很慢。物理内存的作用就是实际和CPU交互通讯的。
2:虚拟内存实际上不再物理内存里面,他只是模拟了所有物理内存的功能,当需要使用的时候,只需要将虚拟内存加载到物理内存里面即可使用。在我们变成,实际上就是接触的虚拟内存,没有接触物理内存,将进程加载到物理内存,从物理内存卸载,实际上都是操作系统来完成的,而非我们写的程序。
3:虚拟内存是有多个的,操作系统会给每个进程分配一个额定的大小空间,很久以前,程序开发必须专机专用,因为他的内存空间等不一样,就会要求有不一样的内存开发方式。后来,就规定了,32位程序下,内存最大为4BG,64位下,内存最大为16EB,变成不需要管理世纪的物理内存,当程序需要的内存草果物理内存大小的时候,他就会部分加载,不会全部加在进去。
4:32位,64位,管理内存的能录不一样,32位只能管理4GB的内存0xFFFFFFFFbyte,64位是0xFFFFFFFFFFFFFFFF,寻址能力更强,2^64byte。每个进程拥有的内存空间是私有的,其他进程是无法访问的,其次,他也是存储在虚拟内存里面,即使他们地址指针位置一样,指向的值也可能不一样,在VS里面,可以同时调试两个工程,在A工程找到一个变量的地址,看其值,然后在B工程内存里面找到同样的地址,会发现值很可能是不一样的,因为虚拟内存空间是私有的,每个进程都会分配。
5:在进程运行的时候,操作系统会参与,所有的程序都是在操作系统智商来运行的,通常4GB的物理内存,里面还会运行操作系统,我们的应用程序能够使用到的内存肯定小于4GB,win98之后,操作系统的空间对于应用程序来说是隐藏哪国的。进程线程不可访问系统的内存空间。
虚拟内存的分区:
1:内存分区:全局区,静态区,栈区,堆区,代码区,对于一个进程,虚拟内存分区与操作系统有关。一般情况下,64位系统分区会按照一下来分:
2:空指针区是不可以访问的,会出现空指针异常,空指针区是不可用的,Windows也不会分配这一块的区域使用。
3:DOS 16兼容区只有Windows98有,图片中的信息是错误的,是0x1F~ 0x3FF,总共4MB,只要用于兼容dos下的程序。在32位和64位已近可以兼容,直接在用户区。
4:用户区:非常重要的区域,程序new空间,加载dll,自己写的exe都是在这个区域来运行的。区域非常大,默认会从0x400000开始执行,实际上也可以设置到0x0000开始。32位的程序大约只有2GB程序可用的空间。
5:内核也有2GB左右的空间,实际上是可以压缩的,把更多的内存留给用户程序使用,但是一般这样做的非常少。
6:64kb禁止进入区,Windows2000开始有的,在这个之上的可以访问,之下的不可访问,它运行的操作系统的内核,内核里面运行的实际就是内核对象等,不单单指dll。内核本身是我们接触不到的,里面是操作系统的代码,比如线程对象,内存管理,网络,驱动等,他们在这个禁止区之下的。
7:共享内存映射区:以前用于进程之间交互的,给一块公共区域,后来遗弃了,现在进程间交互都通过内核对象,网络,管道等。
分配颗粒及页面大小:
1:我们能够操作的只有用户区,分配的4GB空间,如果要使用,需要调用Windows的函数VirtualAlloc函数来分配空间,包括malloc,new等都是调用的这个函数来分配空间的。分配的也是虚拟内存。VirtualAlloc会在用户区申请一块空间,虚拟内存里面这块分配的内存就被使用了。
2:所有的内存操作都是在虚拟内存里面。
3:分配颗粒和页面大小两个名词决定了VirtualAlloc的时候如何分配,分配内存的时候,操作系统必须保证分配地址是一个分配颗粒。分配内存的首地址必须大于分配颗粒的,要符合分配颗粒的要求,所有CPU平台都会使用相同的分配颗粒64KB。分配的空间首地址必须可以被64KB整除。操作系统每一次分配都会由分配颗粒来决定起始的地方。
4:如果使用的空间小于64KB,他还是会分配64KB,后面的部分会成为保留区域,保留区域只是为了符合我们的分配颗粒而存在的。
5:分配空间还与页面大小有关,如果页面大小为4KB,分配的空间还必须可以被4整除,如果我们分配10KB,实际上就分配的是12KB。
页面文件及提交物理内存:
1:CPU和物理内存打交道,我们常使用的虚拟内存必须要加载到物理内存,必须有一个通道来加载。虚拟内存的数据实际上就存储在硬盘里面的,他称之为页交换文件。虚拟存储器会按照页面大小的规定来提交到物理存储器。在Windows里面是按照4KB来提交的,事实上,Windows下的所有文件的大小都是4KB的整数倍,新建的记事本文档就是4KB,8KB……。
2:CPU访问数据块,会首先看物理存储器里面是否有要用的数据,有就用,如果没有,他就会发生一个页面错误,发生页面错误之后,会被操作系统捕获到,操作系统就会去虚拟存储器里面找,如果有,就会判断物理内存是否有空间加载,有则加载,否则他会释放物理存储器的一些内存,如果释放失败,会有提示给用户:内存不够用。如果释放成功,就会加载到物理内存,然后CPU访问物理内存进行进程的运行。
64位及内存对齐:
1:CPU读取文件会按页面大小来读取,内存对齐实际就是:内存%页面大小,页面大小将影响内存对齐。获取页面大小可以使用以前用过的GetSysytemInfo函数:
#include <iostream>
#include <windows.h>
int main()
{
SYSTEM_INFO systeminfo = { 0 };
GetSystemInfo(&systeminfo);
DWORD pageSize = systeminfo.dwPageSize;//获取到系统的页面大小:为4096(4KB)。
return 0;
}
2:现在所有的页面大小都是4KB,如果我们直接定为4KB,也不行,现在使用的都是inter的x86x64或者amd结构,他们都是4KB,但是以后在写一些服务器程序的时候,很多服务器都是用的结构,他的页面大小就是8KB,如果我们把这个数据直接写为4KB是不好的。应该使用GetsystemInfo来获取。
3:在IA64上面,是64位的操作系统,32位应用程序也会获取到8KB的页面大小,实际上,他的页面大小是4KB,此时,内存对齐就会出现问题,微软为了解决32位程序在64位操作系统下运行,加了一个模拟层,称为WOW64,当我们调用的32位程序要进入内核的时候,先调用的就是WOW64里面的dll,他是直接将结果传给了64位的操作系统。
4:判断是否在64位系统下运行:具体的使用方法要查MSDN,bIs64为TRUE和FALSE不是我们想象的。只有在32位程序(进程)运行在64位系统下才为TRUE,其他时候一般为FALSE。
BOOL bIs64;
IsWow64Process(INVALID_HANDLE_VALUE, &bIs64);//判断当前进程是不是在64位下运行。
bIs64 = IsOS(OS_WOW6432);//TRUE代表32位程序在64位下运行
5:还可以使用IsOS来判断,需要包含头文件#include <Shlwapi.h>。此外SystemInfo里面的其他参数也是与系统有关,例如cProcessorRevision参数里面包含了CPU的版本号等信息,可以根据这些信息来判断是什么CPU等。