内存管理 (C++)
1.进程地址空间
Windows为每个进程分配了4GB的虚拟地址空间,让每个进程都认为自己拥有4GB的内存空间,4GB怎么来的? 32位 CPU可以取地址的空间为2的32次方,就是4GB.
2.虚拟地址到实际地址的映射
前面的这些地址并不是物理内存中的地址,而是该进程空间中的虚拟地址,虚拟空间只是Windows为该进程分配的一个虚拟的地址空间,只有当其和物理内存相关联后才有意义.
2.1内存分页
每个物理地址对应一个虚拟地址?1GB那页表该有多长,所以将内存分页管理,4K为一页,即4K就是一个最小单位。
2.2建立映射--分页
进程被创建时会建立一个虚拟内从到物理内存的映射表--页表,根据页表可以将虚拟内存和物理内存关联起来.
2.3虚拟内存
就是把磁盘拿来当内存用,这是以前买电脑时的想法。所以就一直都想不明白一个问题:要真是这样,那内存分个什么1GB,2GB,4GB,大家都买个1M的内存条,然后把自己磁盘拿来当内存用多好,比2GB,4GB不知道要大多少。
其实这个说法有一点擦边球的味道,虚拟内存是一些系统页文件,存放在磁盘上,每个系统页文件大小也为4K,物理内存也被分页,每个页大小也为4K,这样虚拟页文件和物理内存页就可以对应,实际上虚拟内存就是用于物理内存的临时存放的磁盘空间。
页文件就是内存页,物理内存中每页叫物理页,磁盘上的页文件叫虚拟页,物理页+虚拟页就是系统所以使用的页文件的总和。还有映像页文件和映射页文件,映像 页文件就是拿程序本身当页文件使用(而不是用系统的页文件),映射页文件就是使用磁盘上的文件(非系统页文件)来当页文件使用(这主要用于读取文件)。
虚拟地址页的状态:
(1)空闲:该区域没有被所使用,也没有被预定,没有和物理内存管理
(2)私有:该区域虽然没有被使用,但是已经被申请(预定了),别人无法使用它。同样也没和物理内存关联
(3)提交:该区域已经和物理内存管理,可以使用了
2.4虚拟内存和物理内存的管理
Windows是多任务的系统,在每个进程创建时,系统为每个进程也创建了一个页表,用于虚拟地址到物理地址的转换。比如现在程序在执行进程A,用户切换 到了另外一个进程B,则系统会将进程A在内存中的数据存放到页文件中,并更新进程A的页表(使虚拟地址和页文件形成映射)。然后读取进程B的页表,根据页 表判断进程B的数据是在内存中还是在页文件中(通过页文件的类型来判断),如果在内存中就直接读取,如果在页面文件中,就将页面文件内容读入物理内存,然 后更新页表(使虚拟地址和物理内存形成映射)。这样一看,虚拟内存实际上就是冒牌的物理内存了吧。
3.程序执行
一个PE文件有数据区,代码区,堆栈区(由系统分配,用于管理局部变量),使用OD载入一个程序就可以知道这些都是以二进制的形式保存在文件中。
程序刚运行的时候,系统不直接将整个程序载入到物理内存中,也不将其载入到页文件中,而是以程序文件本身作为页文件形成映射(虚拟地址到页文件的映射), 建立页表,然后随着程序的执行通过页表来将其虚拟地址转换成物理地址(将页文件读入内存),然后在读取内存中的指令或数据。当进程被切换时,将内存内容保 存到页文件,更新页表,如此往复,实现多任务操作。
可以知道,程序的代码段,数据段,堆栈区(系统分配)这些虚拟地址区域已经是映射状态,即有相应的物理内存与之对应。系统为每个进程提供了2G的自己的虚拟地址空间,剩下的虚拟地址空间干什么用?
剩下的虚拟地址空间就是给程序运行时动态分配内存使用。C++中 new的功能就是动态分配地址空间:
申请内存的最小单位是区域,每个区域为CPU粒度大小,即64K,每次申请的内存都必须是64K的整数倍,C++ new功能申请一个区域,保留该区域,然后提交需要的页,其他的保留。
char *address=new char[1024]; //分配1K的内存
这条语句首先申请一个区域的地址空间,表示这个区域已经被预定了,这就是上述区域状态中的私有状态,虽然预定了,但是还没有和物理内存关联起来,所以程序 也无法使用该内存,然后程序将这1K的内存提交,就是映射到了内存当中,区域的状态就变成了映射状态,这样程序就可以使用这1K的内存了,而剩下的页仍然 为保留状态。那当进程被切换时,这1K的进程存放在哪呢?程序本身的页文件已经被 代码,全局数据,堆栈这些所使用了,所以系统会为自由存储区分配的内存分配新的页文件来做虚拟内存。
局部变量的定义是由系统分配的,它将局部变量分配到堆栈区,因为堆栈区已经映射了,所以不用在映射,故不用使用新的页文件了。堆栈区的大小为1M左右,如果分配的局部变量超过1M会产生堆栈溢出。
可以看到,系统的单个页文件大小为4K,程序自己的虚拟空间地址00010000到7FFEFFFF差不多是2G动态分配一个500M的内存后,物理内存,页文件,可用的虚拟地址空间都减少了500M
查询内存状态使用VirtualQuery(Address[n],&membaseinf,sizeof(MEMORY_BASIC_INFORMATION))
定义3个变量
char Stack[20*1024];//存在堆栈中,堆栈在程序启动时已经被映像到内存中了
char* Dynamic=new char[64*1024]; //动态分配一个70K的内存
char* Dynamic2=new char[1024]; //动态分配一个1K的内存
参数说明:
地址所在页面基地址:查询的地址所在的页面的起始地址
页面所在区域的基地址:页面所在区域的起始地址
区域保护属性:分配区域时要设置区域的读写属性
从页面基地址开始拥有相同属性(空闲,保留,提交)的所有页的字节数:可以看到这些都是4096的整数倍,因为一个页4096,该大小一般都和申请的内存空间大小相当,因为这些内存都被提交了。
申请一个内存空间的过程
首先申请一个虚拟地址空间区域,然后提交申请的内存空间大小的页(将其和页文件关联)。其他的地址空间保留。
第一条指令分配了一个字符数组的局部变量,该变量分配在堆栈中,由系统分配,所以其区域为程序的静态存储区,即在程序启动时候这个区域的所有虚拟地址就和 程序文件本身映像了,所以局部变量的区域基地址都是一样的,那为什么它的页面文件类型是页文件呢?不应该是exe映像么?因为现在文件在内存中,所有是物 理页,就是页文件。
第二条指令动态分配了一块大小为1K的内存区域,这块内存分配在自由存储区,它所在的区域是在堆中申请的一个区域,第三条指令在堆中分配了一个70K左右的内存,因为他们是在堆中分配的,所以这2个变量的区域基地址是不一样的。
分配的区域有多大?
第三条指令分配了一个70K左右的内存,它会向系统申请多大的区域呢?由区域大小为64K的整数倍知该区域至少为128K,查询这70K之后的虚拟地址的状态
可以看到该地址所在的区域和Dynamic是一样的,它的基地址为580000(转载者加:不应该是594000吧),在那70K之后,这之后的区域的状态为保留,说明系统保留了剩下的 区域,这剩下的区域有966656,就是966K左右的大小,那整个区域的大小就是(0x14000)81920+966656。
内存管理 (C++)的更多相关文章
- .NET基础拾遗(1)类型语法基础和内存管理基础
Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开发基 ...
- PHP扩展-生命周期和内存管理
1. PHP源码结构 PHP的内核子系统有两个,ZE(Zend Engine)和PHP Core.ZE负责将PHP脚本解析成机器码(也成为token符)后,在进程空间执行这些机器码:ZE还负责内存管理 ...
- linux2.6 内存管理——逻辑地址转换为线性地址(逻辑地址、线性地址、物理地址、虚拟地址)
Linux系统中的物理存储空间和虚拟存储空间的地址范围分别都是从0x00000000到0xFFFFFFFF,共4GB,但物理存储空间与虚拟存储空间布局完全不同.Linux运行在虚拟存储空间,并负责把系 ...
- linux2.6 内存管理——概述
在紧接着相当长的篇幅中,都是围绕着Linux如何管理内存进行阐述,在内核中分配内存并不是一件非常容易的事情,因为在此过程中必须遵从内核特定的状态约束.linux内存管理建立在基本的分页机制基础上,在l ...
- Objective-C内存管理之引用计数
初学者在学习Objective-c的时候,很容易在内存管理这一部分陷入混乱状态,很大一部分原因是没有弄清楚引用计数的原理,搞不明白对象的引用数量,这样就当然无法彻底释放对象的内存了,苹果官方文档在内存 ...
- Quartz2D内存管理
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px "PingFang SC"; color: #239619 } p.p2 ...
- 浅谈Linux内存管理机制
经常遇到一些刚接触Linux的新手会问内存占用怎么那么多?在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然.这是Linux内存管理的一个优秀特性,在这 ...
- linux内存管理
一.Linux 进程在内存中的数据结构 一个可执行程序在存储(没有调入内存)时分为代码段,数据段,未初始化数据段三部分: 1) 代码段:存放CPU执行的机器指令.通常代码区是共享的,即其它执行程 ...
- cocos2d-x内存管理
Cocos2d-x内存管理 老师让我给班上同学讲讲cocos2d-x的内存管理,时间也不多,于是看了看源码,写了个提纲和大概思想 一. 为什么需要内存管理 1. new和delete 2. 堆上申 ...
- Swift中的可选链与内存管理(干货系列)
干货之前:补充一下可选链(optional chain) class A { var p: B? } class B { var p: C? } class C { func cm() -> S ...
随机推荐
- VS2013 opencv2.4.8
[转]http://my.phirobot.com/blog/2014-02-opencv_configuration_in_vs.html vs2010+opencv2.4.0:http://www ...
- PHP+AJAX 地区三级联动代码
<html><head><meta http-equiv="Content-Type" content="text/html; charse ...
- UVa 532 - Dungeon Master
题目大意:给一个三维迷宫,给出入口和出口,找出最短路径. 无权图上的单源最短路问题,使用BFS解决. #include <cstdio> #include <queue> #i ...
- python 爬取的数据要如何展现(可视化)?
我是把数据放在 mongodb ,然后单独一个脚本作分析,导出 json ,用 c3.js 画图,然后随便写个很简单的页面就好了. 展示在这里: http://107.170.207.236/job_ ...
- [Angular Tutorial] 3-Components
在先前的步骤中,我们看到了一个控制器和一个模板如何一起工作来将一个静态的HTML文件转化为动态页面(view).一般说来,这在单页应用中一种非常常见的模式(在Angular应用中尤其是这样): ·客户 ...
- bzoj2152
题解: 随便点分治,用一个t数组,t[i]代表有u到root的值mod3==i: 那么答案就是:t[0]*t[0]+t[1]*t[2]*2; 代码: #include<iostream> ...
- PHP检测获取内存信息
PHP也可以检测获取到Windows的内存信息,而且代码还挺简单,无意发现的,觉得以后能用上,在此与大家分享. 本代码将得到总内存.初始使用等内存信息: <?php echo "初始: ...
- 使用UTF8-CPP转换unicode编码 附录:UTF8和UTF16和UTF32和Unicode编码
本文用于解决如何用C++处理字符串的编码格式.本文采用的是成熟便捷的UTF8库来处理这个问题.首先是下载UTF8库,网址为:http://utfcpp.sourceforge.net/ 为了方便后续使 ...
- JDBC oracle 错误总结
ORA-28040: No matching authentication protocol jdk:1.8 oracle:12c 使用ojdbc14.jar 报错:ORA-28040: No mat ...
- Python3基础 global关键字 使函数的局部变量升格为全局变量
镇场诗: 诚听如来语,顿舍世间名与利.愿做地藏徒,广演是经阎浮提. 愿尽吾所学,成就一良心博客.愿诸后来人,重现智慧清净体.-------------------------------------- ...