Windows API 之 VirtualAlloc
Reserves, commits, or changes the state of a region of pages in the virtual address space of the calling process. Memory allocated by this function is automatically initialized to zero.
LPVOID WINAPI VirtualAlloc(
_In_opt_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flAllocationType,
_In_ DWORD flProtect
);
- 虚拟内存技术原理:
Windows的内存结构是深入理解Windows操作系统如何运作的最关键之所在,通过对内存结构的认识可清楚地了解诸如进程间数据的共享、对内存进行有效的管理等问题,从而能够在程序设计时使程序以更加有效的方 式运行。Windows操作系统对内存的管理可采取多种不同的方式,其中虚拟内存的管理方式可用来管理大型的对象和结构数组。
在Windows系统中,任何一个进程都被赋予其自己的虚拟地址空间,该虚拟地址空间覆盖了一个相当大的范围,对于32位进程,其地址空间为 2^32=4,294,967,296 Byte,这使得一个指针可以使用从0x00000000到0xFFFFFFFF的4GB范围之内的任何一个值。虽然每一个32位进程可使用4GB的地址 空间,但并不意味着每一个进程实际拥有4GB的物理地址空间,该地址空间仅仅是一个虚拟地址空间,此虚拟地址空间只是内存地址的一个范围。进程实际可以得到的物理内存要远小于其虚拟地址空间。进程的虚拟地址空间是为每个进程所私有的,在进程内运行的线程对内存空间的访问都被限制在调用进程之内,而不能访问属于其他进程的内存空间。这样,在不同的进程中可以使用相同地址的指针来指向属于各自调用进程的内容而不会由此引起混乱。
在进程创建之初并被赋予地址空间时,其虚拟地址空间尚未分配,处于空闲状态。这时地址空间内的内存是不能使用的,必须首先通过VirtualAlloc()函数来分配其内的各个区域,对其进行保留。
其参数lpAddress包含一个内存地址,用于定义待分配区域的首地址。通常可将此参数设置为NULL,由系统通过搜索地址空间来决定满足条件的未保留 地址空间。这时系统可从地址空间的任意位置处开始保留一个区域,而且还可以通过向参数flAllocationType设置MEM_TOP_DOWN标志 来指明在尽可能高的地址上分配内存。如果不希望由系统自动完成对内存区域的分配而为lpAddress设定了内存地址(必须确保其始终位于进程的用户模式分区中,否则将会导致分配的失败), 那么系统将在进行分配之前首先检查在该内存地址上是否存在足够大的未保留空间,如果存在一个足够大的空闲区域,那么系统将会保留此区域并返回此保留区域的虚拟地址,否则将导致分配的失败而返回NULL。这里需要特别指出的是,在指定lpAddress的内存地址时,必须确保是从一个分配粒度的边界处开始。
- 内存的“保留”与“提交”:
Win32为系统中的每一个应用程序(进程)提供一个独立的、2GB的用户地址空间。对于应用程序来说,好象是有2GB的可用内存(实际上在Windows95/98,NT,Win2000 Advanced Server/Enterprise Server 上的内存分配略有不同),而不用考虑实际可用的物理内存的量。如果某个应用程序要求的内存比可用的内存更多时,Win32是这样满足这种要求的,它从这个和/或其他的进程把非关键内存分页(paging)到一个页文件,并且释放这些物理内存页。
在任意给定的时间,进程中每个地址都可以被当作是自由的、保留的或已提交的。进程开始时,所有地址的都是自由的,意味着它们都是自由空间并且可以被提交到 内存,或者为将来使用而保留起来,但是它们不能存取(read/write)。在任何自由的地址能够被使用前,它必须首先被分配为保留的或已提交的。
当在一个进程中保留地址时,没有物理内存页被提交(没有给这个保留的地址空间分配实际的物理内存),并且,也许更为重要的是,在页文件中没有为备份该内存而保留空间。而且,保留一个地址范围将不会保证将来会有可用的物理内存来提交给这些地址。实际上,它只是保存了一个指定的自由地址,一直到需要使用它时,而阻止了其它分配对该段地址的请求。如果没有 这种类型的保护,那么例程操作(routine operations),例如加载一个DLL或者资源,可能会占有指定的地址,并且危害以后对它的使用。 要使用保留的地址,内存首先必须被提交给该地址。
当内存被提交时,内存物理页被分配,并且该段空间被保留在在一个页文件中。也就是说,已提交的内存页总是以物理内存页或者在已经被分页的磁盘上的页文件的 形式存在。当提交一个大块内存时,在初始阶段,其部分或者全部内存没有驻留在物理内存中也是有可能的。某些内存页一开始驻留在页文件中,直到它被访问。在系统中,一旦内存页已提交,虚拟内存管理器象对待所有其它的内存页一样对待它们。
在Win32虚拟内存系统中,使用了页表(page
tables)来访问物理内存页。每个页表本身也是一个内存页,象已提交的页一样。偶而,当提交内存时,同时还必须对页表分配附加的页。所以,提交一页内
存的请求可能需要为页表分配一页,为请求的页分配一页,并且在页文件中需要两页空间来备份这些页中的每一页。因此,VirtualAlloc完成一个内存
提交请求所需要的时间变化很大,它取决于系统的状态以及请求的空间大小。
上边的描述有些抽象,参考下这篇文章
- 《Windows任务管理器中的几个内存的概念》
进程的内存
对于系统中的每一个进程而言, 都有 4GB 的 "内存空间". 也就是每个进程都认为自己有 4GB 的内存可以使用.
系统将每个进程的 4GB 地址空间, 从逻辑上划分为两大部分:
a) 蓝色的是用户空间, 此空间是被用户程序所使用的. 比如我在代码中写 "分配 100MB 内存", 其实占用的就是这一部分.
b) 红色的是内核空间, 此空间是被用作操作系统执行必要的线程切换以及从用户态函数进入内核态执行功能所保留的内存地址. 应用程序无法操作此区域.
Intel x86 体系内存管理
Intel 规定, 一个在计算机内部, 可以使用 "分页机制" 对硬件内存进行 "虚拟化". 其核心技术如下图:
首先, 在程序中的一个地址 0x1234, 5678 被计算机的页部件(硬件)经过 1,2,3 步, 从线性地址(程序中的地址) 转变为真正机器上的物理地址(即实际内存的硬件地址). 每个线性地址都被分成 "页目录索引(PDE, 10-bit)", "页表索引(PTE, 10-bit)", "页内偏移(offset, 12-bit)" 三部分.
1) 在页目录中根据 PDE 找到页表的位置, 即通过 0x48 找到 0xa000, 0000.(PDT的地址保存在CR3中)
2) 根据页表中的 PTE 找到页地址, 即通过 0x345 找到 0x4000, 0000.
3) 根据偏移, 在页中找到我们要的具体地址, 即已知页位于 0x4000, 0000, 我们需要存取其 0x678 偏移处的数据, 则我们所需要操作的真是物理地址就是 0x4000, 0678.
基于 x86 的 Windows 内存管理
- 举例:
当我们调用
时,pBase返回0x00080000,我们观察地址范围0x00080000-0x0009b000(dwSize就是分配的Size,其时大小为0x1b000)的内存:
已经被VirtualAlloc初始化为0.
参考:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa366887%28v=vs.85%29.aspx
http://www.yesky.com/67/1753067.shtml
http://super-man-woman.blog.163.com/blog/static/3789803820098532317144/
http://www.cnblogs.com/walfud/articles/3256233.html
理解paging:http://www.mouseos.com/arch/paging.html
Pushing the limits of windows:Virtual Memory:http://blogs.technet.com/b/markrussinovich/archive/2008/11/17/3155406.aspx
Windows API 之 VirtualAlloc的更多相关文章
- Windows API 进程相关笔记
0. 前言 最近做了一个进程信息相关的项目,整理了一下自己做项目时的笔记,分享给大家 1. 相关概念 1.1 HANDLE 概念 HANDLE(句柄)是Windows操作系统中的一个概念. 在Wind ...
- Windows API 学习
Windows API学习 以下都是我个人一些理解,笔者不太了解windows开发,如有错误请告知,非常感谢,一切以microsoft官方文档为准. https://docs.microsoft.co ...
- C# Windows API
API:应用程序接口(API:Application Program Interface)应用程序接口(API:application programming interface)是一组定义.程序及协 ...
- Windows API 函数列表 附帮助手册
所有Windows API函数列表,为了方便查询,也为了大家查找,所以整理一下贡献出来了. 帮助手册:700多个Windows API的函数手册 免费下载 API之网络函数 API之消息函数 API之 ...
- Windows API Hooking in Python
catalogue . 相关基础知识 . Deviare API Hook Overview . 使用ctypes调用Windows API . pydbg . winappdbg . dll inj ...
- 初识【Windows API】--文本去重
最近学习操作系统中,老师布置了一个作业,运用系统调用函数删除文件夹下两个重复文本类文件,Linux玩不动,于是就只能在Windows下进行了. 看了一下介绍Windows API的博客: 点击打开 基 ...
- C#调用windows API的一些方法
使用C#调用windows API(从其它地方总结来的,以备查询) C#调用windows API也可以叫做C#如何直接调用非托管代码,通常有2种方法: 1. 直接调用从 DLL 导出的函数. 2. ...
- Qt中使用Windows API
在Windows平台上进行开发,不可避免与Windows API打交道,Qt中使用的时候要添加对应API的头文件和链接lib文件,另外使用的Windows API的代码部分要使用#ifdef Q_O ...
- 在VBA中使用Windows API
VBA是一种强大的编程语言,可用于自定义Microsoft Office解决方案.通过使用VBA处理一个或多个Office应用程序对象模型,可以容易地修改Office应用程序的功能或者能够使两个或多个 ...
随机推荐
- 最有用的Gulp插件汇总
HTML&CSS autoprefixer - parse CSS and add vendor prefixes to rules by Can I Use. gulp-browser-sy ...
- 绝对路径&相对路径
被绝对路径和相对路径搞疯了,好多地方不一样,从今天开始,记录下来每次关于这个问题的记录,以备查用 css文件里: 绝对路径:以"/"开头,表示从项目的根目录开始
- 坑爹的 Hardware Reserved Memory (查看内存等)
来源: http://blog.sina.com.cn/s/blog_772645ff0100s4t7.html 我的电脑是GatewayNV49C83c,酷睿i3的CPU和NV的独立显卡 Inter ...
- incredibuild agent service is not running
incredibuild 不用介绍了,今天因为服务没有启动报错显示为: incredibuild agent service is not running 解决方法为: 在Incredibuild的安 ...
- sqlserver负载均衡
http://www.cnblogs.com/gaizai/p/3644510.html
- 1.1 java学习网站
1.http://www.rupeng.com/Courses/Index/51 2.https://www.zhihu.com/question/25255189
- Nginx下$_POST获取不到数据的解决方法
运行环境:windows+phpstorm+Nginx 步骤1:找到php.ini 配置文件,查找enable_post_data_reading变量,把Off改为On,确保其打开状态: 步骤2:将p ...
- jq小demo—图片翻页展示效果 animate()动画
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...
- neutron openvswitch agent实现安全组的方法
关于openstack安全组,采用一问一答的形式记录如下 1. 是加载在计算节点的还是网络节点的? 是加载在计算节点的 2. 是使用iptable规则实现的吗? M版的neutron实现了openvs ...
- MySQL导入乱码解决
导入时出现乱码,需要在语句中添加指定导入数据的编码格式: mysql -uroot -p database_name < database_backup.sql --default-charac ...