Windows核心编程小结2
这一节看看内存管理相关的信息
首先看看虚拟内存
虚拟地址空间
32位系统 --- 4GB = 232
64 位系统 ---- 16EB = 264
虚拟内存表
当一个应用程序从硬盘加载到RAM时,首先系统为应用程序保留一定的地址区域,将一些必须的数据加载到内存中,然后将一些不是必须的数据加载到页文件(虚拟内存)中,页文件的大小有操作系统控制。在程序运行过程中,如果需要某个文件,就先去RAM中寻找,如果寻找不到,就去页文件中寻找,如果还寻找不到就发出数据访问违规异常。
过程如下:

每个页文件的保护属性都不同,页文件的页面拥有不同的属性,包括

除了上面介绍的保护属性外,还有3个保护属性标志,即PAGE_NOCACHE,PAGE_WRITECOMBINE和PAGE_GUARD。可以用OR逐位将它们连接,以便将这3个标志用于任何一个保护属性(PAGE_NOCACHE除外)。
第一个保护属性标志PAGE_NOCACHE用于停用已提交页面的高速缓存。一般情况下最好不要使用该标志,因为它主要是供需要处理内存缓冲区的硬件设备驱动程序的开发人员使用的。
第二个保护属性PAGE_WRITECOMBINE也是供设备驱动程序开发人员使用的。它允许把单个设备的多次写入合并在一起,以便提高运行性能。
最后一个保护属性标志PAGE_GUARD可以在页面上写入一个字节时使应用程序收到一个通知(通过一个异常条件)。该标志有一些非常巧妙的用法。Windows2000在创建线程堆栈时使用该标志。
虚拟内存的区域类型共有四个值,即空闲、私有、映像或映射。

数据对齐
数据对齐并不是操作系统的内存结构的一部分,而是CPU结构的一部分。
当CPU访问正确对齐的数据时,它的运行效率最高。当数据大小的数据模数的内存地址是0时,数据是对齐的。
当CPU试图读取的数据值没有正确对齐时,CPU可以执行两种操作之一。即它可以产生一个异常条件,也可以执行多次对齐的内存访问,以便读取完整的未对齐数据值。
X86CPU和AlphaCPU的对齐方式不同。
虚拟内存相关的函数
获取系统信息相关的函数GetSystemInfo()
void WINAPI GetSystemInfo(
_Out_ LPSYSTEM_INFO lpSystemInfo//结构体信息
);
结构体如下:
typedef struct _SYSTEM_INFO {
union {
DWORD dwOemId; // Obsolete field...do not use
struct {
WORD wProcessorArchitecture;//CPU结构
WORD wReserved;//保留字段
} DUMMYSTRUCTNAME;
} DUMMYUNIONNAME;
DWORD dwPageSize;//页面大小
LPVOID lpMinimumApplicationAddress;//最小内存地址
LPVOID lpMaximumApplicationAddress;//最大内存地址
DWORD_PTR dwActiveProcessorMask;//哪个CPU是活动的
DWORD dwNumberOfProcessors;//CPU数目
DWORD dwProcessorType;//CPU类型
DWORD dwAllocationGranularity;//保留的内存空间区域的分配粒度,
WORD wProcessorLevel; //CPU结构细节
WORD wProcessorRevision; //CPU等级
} SYSTEM_INFO, *LPSYSTEM_INFO;
其中与内存相关的参数如下:

其他与内存无关的成员函数

现在来看看如何使用这个函数
//获取系统参数
#include "windows.h"
#include "iostream"
using namespace std; int main()
{
SYSTEM_INFO sysinfo;//声明一个结构体
GetSystemInfo(&sysinfo); cout<<"页面大小:"<<sysinfo.dwPageSize<<endl;
cout<<"最小内存地址:"<<sysinfo.lpMinimumApplicationAddress<<endl;
cout<<"最大内存地址:"<<sysinfo.lpMaximumApplicationAddress<<endl;
cout<<"保留的地址空间区域的分配粒度:"<<sysinfo.dwAllocationGranularity<<endl;
cout<<"CPU数目:"<<sysinfo.dwNumberOfProcessors<<endl;
cout<<"活动CPU:"<<sysinfo.dwActiveProcessorMask<<endl;
cout<<"处理器类型:"<<sysinfo.dwProcessorType<<endl;
cout<<"处理器结构:"<<sysinfo.wProcessorArchitecture<<endl;
cout<<"处理器等级:"<<sysinfo.wProcessorLevel<<endl;
cout<<"处理器版本:"<<sysinfo.wProcessorRevision<<endl; getchar();
return ;
}
虚拟内存的状态GlobalMemoryStatus()
//这是旧版的函数
void GlobalMemoryStatus(
__out LPMEMORYSTATUS lpBuffer
);
typedef struct _MEMORYSTATUS {
DWORD dwLength;
DWORD dwMemoryLoad;
SIZE_T dwTotalPhys;
SIZE_T dwAvailPhys;
SIZE_T dwTotalPageFile;
SIZE_T dwAvailPageFile;
SIZE_T dwTotalVirtual;
SIZE_T dwAvailVirtual;
} MEMORYSTATUS, *LPMEMORYSTATUS;
//新版的函数,支持4G以上虚拟内存,64位宽度
//新版函数更加强大
BOOL GlobalMemoryStatusEx(
__out LPMEMORYSTATUSEX lpBuffer
);
typedef struct _MEMORYSTATUSEX {
DWORD dwLength;//结构体大小
DWORD dwMemoryLoad;//已加载的内存比例
DWORDLONG ullTotalPhys;//物理内存大小
DWORDLONG ullAvailPhys;//当前可用物理内存大小
DWORDLONG ullTotalPageFile;//总的页面大小
DWORDLONG ullAvailPageFile;//当前可用的页面大小
DWORDLONG ullTotalVirtual;// 每个进程的地址空间中私有的总字节数
DWORDLONG ullAvailVirtual;// 进程的空闲地址空间的数量
DWORDLONG ullAvailExtendedVirtual;//保留,0
} MEMORYSTATUSEX, *LPMEMORYSTATUSEX;
注意事项:
在调用GlobalMemoryStatus之前,必须将dwLength成员初始化为结构体的大小,即一个MEMORYSTATUS结构的大小。
函数使用如下:
//获取虚拟内存状态
cout<<"\n虚拟内存状态\n"<<endl;
//虚拟内存状态
MEMORYSTATUSEX ms;
ms.dwLength = sizeof(MEMORYSTATUSEX);//这个参数必须首先初始化
GlobalMemoryStatusEx(&ms);
cout<<"结构体大小:"<<ms.dwLength<<endl;
cout<<"已加载的内存比例:"<<ms.dwMemoryLoad<<endl;
cout<<"物理内存大小:"<<ms.ullTotalPhys<<endl;
cout<<"可用内存大小:"<<ms.ullAvailPhys<<endl;
cout<<"总的页面数:"<<ms.ullTotalPageFile<<endl;
cout<<"可用页面数:"<<ms.ullAvailPageFile<<endl;
cout<<"每个进程的地址空间中私有的总字节数:"<<ms.ullTotalVirtual<<endl;
cout<<"进程的空闲地址空间的数量:"<<ms.ullAvailVirtual<<endl;
地址空间状态VirtualQuery()
通过该函数或获取进程地址空间的信息,如大小,存储类型,保护属性等。
SIZE_T WINAPI VirtualQuery(
_In_opt_ LPCVOID lpAddress,//要查询的进程的地址空间信息的虚拟内存地址
_Out_ PMEMORY_BASIC_INFORMATION lpBuffer,//结构体
_In_ SIZE_T dwLength//本结构体的大小
);
//其中参数的详细情况如下
typedef struct _MEMORY_BASIC_INFORMATION {
PVOID BaseAddress;//进程地址
PVOID AllocationBase;//基地址
DWORD AllocationProtect;//保护属性
SIZE_T RegionSize;//所有页面大小
DWORD State;//相邻界面状态
DWORD Protect;//相邻界面保护属性
DWORD Type;//相邻界面的物理存储器类型
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;
参数介绍如下:

由一个进程查询另一个进程的信息 VirtualAllocEx()
调试程序会调用这个函数,查看其他进程的信息
//由一个进程查询另一个进程的信息
LPVOID VirtualAllocEx(
__in HANDLE hProcess,//进程句柄
__in_opt LPVOID lpAddress,//查询地址
__in SIZE_T dwSize,//与分配的页面大小
__in DWORD flAllocationType,//分配类型
__in DWORD flProtect //保护属性
);
如何查询地址状态
//如何查询地址状态
cout<<"地址空间的状态"<<endl;
MEMORY_BASIC_INFORMATION mbi;
HANDLE hProcess = NULL;
TCHAR path[] = {};
DWORD dwResult = VirtualQuery(hProcess,&mbi,sizeof(mbi));
while(dwResult)
{
cout<<"内存地址起始地址:"<<hProcess<<endl;
switch(mbi.State)
{
case MEM_COMMIT:
cout<<"已经物理分配"<<endl;
break;
case MEM_RESERVE:
cout<<"保留"<<endl;
break;
case MEM_FREE:
cout<<"空闲没有分配"<<endl;
break;
default:
break;
}
switch(mbi.Type)
{
case MEM_IMAGE:
cout<<"该地址为文件镜像"<<endl;
GetModuleFileName((HINSTANCE)hProcess,path,);
cout<<path<<endl;
break;
case MEM_MAPPED:
cout<<"已经映射了"<<endl;
break;
case MEM_PRIVATE:
cout<<"私有的空间"<<endl;
break;
default:
break;
}
getchar();
cout<<endl;
hProcess=(PBYTE)hProcess+mbi.RegionSize;
dwResult=VirtualQuery(hProcess,&mbi,sizeof(MEMORY_BASIC_INFORMATION));
}
Windows核心编程小结2的更多相关文章
- Windows核心编程小结3
内存映射和堆栈 内存映射文件 内存映射文件可以用于3个不同的目的: 系统使用内存映射文件,以便加载和执行.exe和DLL文件.这可以大大节省页文件空间和应用程序启动运行所需的时间. 可以使用内存映射文 ...
- Windows核心编程小结1
这本书绝对经典,看看定会增加不少知识.当然这本书有很多东西比<Windows程序设计第五版>中的更加详细. 1.Unicode:宽字节字符集 这是一个国际的字符标准,16位,最大可支持65 ...
- windows核心编程 - 线程同步机制
线程同步机制 常用的线程同步机制有很多种,主要分为用户模式和内核对象两类:其中 用户模式包括:原子操作.关键代码段 内核对象包括:时间内核对象(Event).等待定时器内核对象(WaitableTim ...
- windows核心编程---第九章 同步设备IO与异步设备IO之同步IO
同步设备IO 所谓同步IO是指线程在发起IO请求后会被挂起,IO完成后继续执行. 异步IO是指:线程发起IO请求后并不会挂起而是继续执行.IO完毕后会得到设备的通知.而IO完成端口就是实现这种通知的很 ...
- windows核心编程---第八章 使用内核对象进行线程同步
使用内核对象进行线程同步. 前面我们介绍了用户模式下线程同步的几种方式.在用户模式下进行线程同步的最大好处就是速度非常快.因此当需要使用线程同步时用户模式下的线程同步是首选. 但是用户模式下的线程同步 ...
- windows核心编程---第二章 字符和字符串处理
使用vc编程时项目-->属性-->常规栏下我们可以设置项目字符集合,它可以是ANSI(多字节)字符集,也可以是unicode字符集.一般情况下说Unicode都是指UTF-16.也 ...
- 回忆读windows 核心编程
看<windows 核心编程> 第五版到纤程了,下一章节即将介绍内存体系编程.如果做window平台下的开发,我感觉此书一定要读.记得开始讲解了window的基础,然后讲解内核对象.内核对 ...
- 《Windows核心编程》第5版 学习进度备忘
学习资源:<Windows核心编程>第5版 知识基础支持: 本书与<Windows程序设计>第5版珍藏版结合很好,二者重叠内容不多,二者互补性强,而且相关方面的优秀书籍 跳过的 ...
- 【windows核心编程】 第八章 用户模式下的线程同步
Windows核心编程 第八章 用户模式下的线程同步 1. 线程之间通信发生在以下两种情况: ① 需要让多个线程同时访问一个共享资源,同时不能破坏资源的完整性 ② 一个线程需要通知其他线程 ...
随机推荐
- Eucalyptus管理页面密码设置
桉树环境什么的都已经是配置好了的,但是过了一段时间不用,也不知道密码是什么了,看着下面的页面也不知道如何进去,这里我们通过命令行的方式重置用户名和密码信息. 登陆clc所在机器,输入下命令: euar ...
- v-if与v-show的区别
一.区别 v-if 动态的向DOM树内添加或者删除DOM元素:“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建:在初始渲染条件为假时,什么也不做. v-sho ...
- Command Line Client(建库,建表)
Enter password: ******Welcome to the MySQL monitor. Commands end with ; or \g.Your MySQL connection ...
- POJ-1149 PIGS---最大流+建图
题目链接: https://vjudge.net/problem/POJ-1149 题目大意: M个猪圈,N个顾客,每个顾客有一些的猪圈的钥匙,只能购买这些有钥匙的猪圈里的猪,而且要买一定数量的猪,每 ...
- Android(java)学习笔记152:采用get请求提交数据到服务器(qq登录案例)
1.GET请求: 组拼url的路径,把提交的数据拼装url的后面,提交给服务器. 缺点:(1)安全性(Android下提交数据组拼隐藏在代码中,不存在安全问题) (2)长度有限不能超过4K(h ...
- basic_double_stream_incorrect
不合理的代码 /* * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. * * NVIDIA Corporation and ...
- Linux MySQL 修改密码
修改root本地登录密码 修改root默认的密码(方法一)1. 启动mysql之后systemctl start mysqld.service2. 修改mysql的配置文件 vi /etc/my.cn ...
- Oracle Hint 之 Append
1 描述 所谓直接路径操作,就是绕过buffer cache,直接将数据插入到表所在的数据文件中: 假如有表A,要将A中的数据插入到表B,在普通的间接插入下,先将A中的数据块传进buffer cach ...
- Java如何将十六进制数转换为十进制数的自编程序
package com.swift;//所属包 import java.util.Scanner;//导入扫描器 public class Hex2Decimal { public static vo ...
- JS中的引用、浅拷贝和深拷贝
js的深拷贝浅拷贝是很常遇到的问题,一直模模糊糊有点说不过去,所以这次好好总结一下. 1.js的引用 JS分为基础类型和引用类型两种数据类型: 基础类型:number.string.boolean.n ...