内存
1.1、虚拟内存和物理内存(逻辑内存):
1.1.1、虚拟内存:模拟物理内存。为程序分配额定的大小空间。32位下每个进程有4GB,可是在这个虚拟内存空间中进程是无法完全拥有的,因为还要运行一些操作系统的代码(也是当前进程私有的)。
1.1.2、物理内存:在我们的电脑中只有一块,而且空间是有限的。不可增长。和CPU进行通信。
1.1.3、每个进程拥有的内存空间是私有的,别的进程是无法来访问的。在不同的进程中,尽管地址值可能是一样的但是内容是不一样的。
1.2、虚拟地址空间分区: 当进程被创建并被赋予它的地址空间时,该可用地址空间的主体是空闲的,即未分配的。
若要使用该地址空间的各个部分,必须通过调用VitualAlloc函数来分配他里边的各个区域,对一个地址空间的区域进行分配的操作称为保留。
每当你保留地址空间的一个区域时,系统要确保该区域从一个分配粒度的边界开始。
当你保留地址空间的一个区域时,系统还要确保该区域的大小是系统的页面大小的倍数。
1.2.1、分配颗粒:所有的CPU平台都会使用相同的分配颗粒即64KB。决定了分配内存起始的地方。64KB的倍数
1.2.2、页面大小:4KB,分配的内存空间的大小必须能够被页面大小所整除,也就是被4KB所整除。
1.2.3、也就是说我们保留的空间是:分配颗粒决定了开始的位置,页面大小决定了申请的内存大小,两个决定加起来就是整个保留空间大小。
1.3、CPU可以从内存中读取数据,并且能够帮我们计算,并且能够将这些呈现给我们
1.4、物理存储器和虚拟存储器:
1.4.1、这两者中必须有个通道,使得物理存储器能够通过这个通道来进行虚拟存储器内容的加载。
1.4.2、虚拟存储器的状态存在在硬盘中的一个叫页交换文件的地方
1.4.3、在虚拟存储器提交内容给物理存储器的时候是按照页面为单位来提交的。
1.5、64位及内存对齐:
1.5.1、内存对齐 = 内存 % 页面大小;
1.5.2、
BOOL WINAPI IsWow64Process(
_In_ HANDLE hProcess,
_Out_ PBOOL Wow64Process
);
1.5.3、
BOOL IsOS(
_In_ DWORD dwOS
);
1.5.4、以上两个函数都可以帮我们进行判断我们的程序在哪个系统下进行运行。
1.5.5、
SYSTEM_INFO systemInfo = { 0 }; GetSystemInfo(&systemInfo); //获取操作系统的信息。 //systemInfo.dwPageSize; _tprintf(TEXT("Page size : %d\r\n"), systemInfo.dwPageSize);
1.6、ReadProcessMemory读出指定的内存地址数据
BOOL ReadProcessMemory( HANDLE hProcess, // 被读取进程的句柄; LPCVOID lpBaseAddress, // 读的起始地址; LPVOID lpBuffer, // 存放读取数据缓冲区; DWORD nSize, // 一次读取的字节数; LPDWORD lpNumberOfBytesRead // 实际读取的字节数; );
1.7、
BOOL WriteProcessMemory( HANDLE hProcess, LPVOID lpBaseAddress,//要写的内存首地址、再写入之前,此函数将先检查目标地址是否可用,并能容纳待写入的数据。 LPVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesWritten );
1.8、页目大小为4K,其中每一项(32位)保存一个页表的物理地址;每个页表大小为4K,其中每一项(32位)保存一个物理页的物理地址,
一共有1024个页表。利用这4K+4K*1K=4.4M的空间可以表示进程的1024*1024* (一页4K) =4G的地址空间。
1.9、进程空间中的32位地址如下:
高10,中10,低12
高10位用来找到1024个页目项中的一项,取出页表的物理地址后,利用中10位来得到页表项的值,
根据这个值得到物理页的地址,由于一页有4K大小,利用低12位得到单元地址,这样就可以访问这个内存单元了。
1.10、每个进程都有自己的一个页目和页表,那么,刚开始进程是怎么找到页目所在的物理页呢?
答案是CPU的CR3寄存器会保存当前进程的页目物理地址。
1.11、当进程被创建时,同时需要创建页目和页表,一共需要4.4M。在进程的空间中,
0xC030 0000~0xC030 0FFF是用来保存页目的4k空间。
0xC000 0000~0xC03F FFFF是用来保存页表的4M空间。
1.12、Windows当中的进程都是按照页面大小来进行管理的。
1.13、
DWORD VirtualQueryEx( //返回值:函数写入lpBuffer的字节数,如果不等于sizeof(PMEMORY_BASIC_INFORMATION)表示失败 HANDLE hProcess, //进程句柄 LPCVOID lpAddress, //查询内存的地址 PMEMORY_BASIC_INFORMATION lpBuffer, //结构的指针,用于接收内存信息。 DWORD dwLength //PMEMORY_BASIC_INFORMATION结构的大小 );
1.14、判断程序在哪个操作系统下运行:
SYSTEM_INFO si; GetNativeSystemInfo(&si); if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 || si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_IA64 ) { //64 位操作系统 } else
{ // 32 位操作系统 }
1.15、
void WINAPI GetNativeSystemInfo( _Out_ LPSYSTEM_INFO lpSystemInfo );
1.16、
typedef struct _SYSTEM_INFO { // sinf union { DWORD dwOemId; //已废弃的成员,保留这个成员是为了向以前版本的Windows NT保持兼容。 从Windows NT 3.51和Windows 95的预发行版本开始,使用这个成员的子分支wProcessorArchitecture。 struct { WORD wProcessorArchitecture; //指定系统中的中央处理器的体系结构 WORD wReserved; //保留 }; }; DWORD dwPageSize; //指定页面的大小和页面保护和委托的颗粒。这是被 VirtualAlloc 函数使用的页大小。 LPVOID lpMinimumApplicationAddress; //指向应用程序和动态链接库(DLL)可以访问的最低内存地址。 LPVOID lpMaximumApplicationAddress; //指向应用程序和动态链接库(DLL)可以访问的最高内存地址。 DWORD dwActiveProcessorMask; //指定一个用来代表这个系统中装配了的中央处理器的掩码。二进制0位是处理器0;31位是处理器31。 DWORD dwNumberOfProcessors; //指定系统中的处理器的数目。 DWORD dwProcessorType; //这个成员已经不再有用了, DWORD dwAllocationGranularity; //指定已经被分配的虚拟内存空间的粒度。 WORD wProcessorLevel; // WORD wProcessorRevision; // } SYSTEM_INFO;
1.15、
void WINAPI GlobalMemoryStatus( _Out_ LPMEMORYSTATUS lpBuffer );
1.16、
typedef struct _MEMORYSTATUS { DWORD dwLength; //MEMORYSTATUS结构的大小,在调GlobalMemoryStatus函数前用sizeof()函数求得,用来供函数检测结构的版本。 DWORD dwMemoryLoad; //返回一个介于0~100之间的值,用来指示当前系统内存的使用率 SIZE_T dwTotalPhys; //返回总的物理内存大小,以字节(byte)为单位。 SIZE_T dwAvailPhys; //返回可用的物理内存大小,以字节(byte)为单位。 SIZE_T dwTotalPageFile; //显示可以存在页面文件中的字节数。注意这个数值并不表示在页面文件在磁盘上的真实物理大小。 SIZE_T dwAvailPageFile; //返回可用的页面文件大小,以字节(byte)为单位。 SIZE_T dwTotalVirtual; //返回调用进程的用户模式部分的全部可用虚拟地址空间,以字节(byte)为单位。 SIZE_T dwAvailVirtual; //返回调用进程的用户模式部分的实际自由可用的虚拟地址空间,以字节(byte)为单位。 } MEMORYSTATUS, *LPMEMORYSTATUS;