以前写过一篇理解程序内存, 当时主要是针对用户态,下面再稍微深入一点:

我们以32位程序为例(不启用AWE), 总共4G虚拟空间,其中低2G属于用户态, 高2G属于操作系统内核, 每个程序都有自己的低2G用户空间, 高2G内核空间是所有程序共享的。高2G内核空间中, 属于同一Session的程序又共享相同的session空间:

x86系统所有的内存以64K边界粒度, 4K页面大小分配。

用户态的内存空间,按用途分可以分为: image, mapped file, heap, stack, free等
按状态分可以分为:Free, reserved, commit;
Commit的内存,在被访问时又可能以不同的状态存在, 可能是已经提交到物理内存(RAM),也可能是已页文件的形式存在后台, 如果是页文件形式,访问时会触发换页操作。

我们平时以任务管理器或者Process Explorer, 经常会看到一些不同内存术语:
virtual size: reserve和commit的虚拟内存
Private bytes: 已经commit的私有虚拟内存
working set: commit的虚拟内存中已经被加载到物理内存中的部分
WS private / 内存(专用工作集): 不能和其他程序共享的working set

这些内存的大小关系怎么样?
virtual size 肯定是最大的; WS private肯定是最小的;working set和private bytes大小不好定, 因为working set虽然是表示物理内存, 但它包含共享和非共享两部分, 而private bytes虽然是虚拟内存,却只包含私有部分。
另外我们平时看程序的内存泄漏,主要可以看private bytes 和 WS private.

我们程序里使用的虚拟地址, 它在访问时是如何别转成真正的物理地址的?

1. 我们的虚拟地址被分为页目录索引,页表索引,字节偏移三部分
2. 根据CR3寄存器得到当前进程的页目录表地址, 根据页目录索引得到页目录表项目(PDE), 然后就可以得到该页表的地址
3. 根据页表索引,得到页表项目(PTE)的地址, 然后即可定位到该页面, 根据偏移字节即可访问真正的物理内存

操作系统采用按需换页的算法来实现内存的访问, 也就是说系统会在真正访问一个地址的时候才会把该地址转成有效的物理地址, 如果访问失败, 会触发换页异常, 再真正加载该页面换到物理内存。系统用虚拟地址描述符(VAD, virtual address descriptor)组成的平衡二叉树来跟踪所有的虚拟内存,以确定所有虚拟内存的状态(free, reserver, commit)和属性。

下面说下应用层对程序内存的访问, 按照内存的用途就可以大概划分:
Image: 主要是指二进制模块在内存中存在方式, 比如Exe和Dll, 对应的API比如LoadLibrary。
Mapped file: 主要是指内存映射文件, 可以用来快速的加载大文件 ,或者跨进程共享内存, 对应的API比如 CreateFileMapping.
Stack: 每个线程都有自己的堆栈, 包括用户态堆栈和内核堆栈,虽然堆栈内存分配有大小限制, 但是非常高效,函数的局部变量都存在里面,程序的运行过程(函数的调用过程)实际上是不停的压栈和出栈的过程,大小一般默认保留1M(参见线程堆栈是如何增长的)
Heap: 系统有自己的堆管理器, 虽然效率堆内存分配效率低, 但是没有大小限制, 对应的API比如new, malloc, HeapAlloc

操作系统为我们访问内存提供了各种渠道,我们可以根据需要自己选择, 由下往上可以分为:
虚拟内存: 对应的API如VirtualAlloc(Ex), VirtualFree(Ex), VirtualLock, VirtualProtect, 通过这些API,我们可以直接分配(reserver, commit)大块内存( 4K页面大小), 同时定义修改页面属性, 这是最高效的大内存分配方式。
Win32 堆内存: 对应的API如HeapCreate, HeapAlloc, 堆内存建立在虚拟内存之上,很多时候我们不需要虚拟内存的大块内存,只需要小块内存,操作系统通过堆管理器帮我们解决了这个问题。每个进程启动时系统都会创建一个默认堆,同时我们也可以创建自己的私有堆, 不同模块之间是否共享同一个CRT堆取决于模块的编译选项,(参见基于WinDbg的内存泄漏分析
CRT 堆内存:C/C++代码中我们最常用的内存分配方式是malloc和new, 通常情况下malloc只负责内存分配, 而new在调用malloc分配内存的同时还有在分配的内存上构造对象的功能。至于malloc的实现方式, 不同的编译器厂商会有不同的实现, 有些可能是通过Win32堆实现,也可能是通过虚拟内存API直接实现。

思考为什么有了虚拟内存API和Win32堆API,还要有CRT堆API?
软件工程里一条比较经典的话是: 任何问题都可以加一个间接层加以解决。操作系统提供的API都是平台相关的, 通过CRT这个间接层实现了平台无关, 同时我们可以在这个间接层上做很多事情, 比如内存泄漏跟踪, 实现自己的内存池等。

如果我们直接调用虚拟内存API分配内存, 这种内存属于那种类型?
实际上按照VMMap的说法, 内存类型还有更多: Image, Mapped File, Shareable, Heap, Managed Heap, Stack, Private Data, Page Table, Unusable, Free.
直接通过VirtualAlloc分配的内存不属于Heap, 应该属于Private Data.

Windows内存小结的更多相关文章

  1. Windows内存小结(有好多图,比较清楚)

    以前写过一篇理解程序内存, 当时主要是针对用户态,下面再稍微深入一点: 我们以32位程序为例(不启用AWE), 总共4G虚拟空间,其中低2G属于用户态, 高2G属于操作系统内核, 每个程序都有自己的低 ...

  2. 第13章 Windows内存体系结构

    13.1 Windows的虚拟地址空间安排 13.1.1虚拟地址空间的分区(即虚拟地址空间布局) 进程的地址空间划分 分区 x86 32位 Windows 3GB用户模式下的x86 32位Window ...

  3. Windows内存管理和linux内存管理

    windows内存管理 windows 内存管理方式主要分为:页式管理,段式管理,段页式管理. 页式管理的基本原理是将各进程的虚拟空间划分为若干个长度相等的页:页式管理把内存空间按照页的大小划分成片或 ...

  4. windows内存映射学习及帮助类实现

    本文通过创建文件内存映射类,学习windows内存映射相关知识:创建内存映射文件后,可以按照内存操作方式操作文件:支持32位程序处理超过4G大小的文件. 感谢http://blog.csdn.net/ ...

  5. Windows内存管理[转]

    本文主要内容:1.基本概念:物理内存.虚拟内存:物理地址.虚拟地址.逻辑地址:页目录,页表2.Windows内存管理3.CPU段式内存管理4.CPU页式内存管理 一.基本概念1. 两个内存概念物理内存 ...

  6. Windows内存原理与内存管理

    WIndows为每个进程分配了4GB的虚拟地址空间,让每个进程都认为自己拥有4GB的内存空间,4GB怎么来的? 32位 CPU可以取地址的空间为2的32次方,就是4GB(正如16位CPU有20根寻址线 ...

  7. windows内存管理方式以及优缺点

    Windows内存管理方式:页式管理,段式管理,段页式管理 页式管理 将各进程的虚拟空间(逻辑地址)划分为若干个长度相等的页,业内管理把内存空间(物理内存)按照页的大小划分为片或者页面,从而实现了离散 ...

  8. 解决Windows内存问题的两个小工具RamMap和VMMap(这个更牛更好)

    来源:http://www.cr173.com/html/13006_1.html .net程序内存监测分配工具(CLR Profiler for .NET Framework 4)官方安装版 类型: ...

  9. 解决Windows内存问题的两个小工具RamMap和VMMap

    解决Windows内存问题需要对操作系统的深入理解,同时对于如何运用Windows调试器或性能监控器要有工作认知.如果你正试着得到细节,诸如内核堆栈大小或硬盘内存消耗,你会需要调试器命令和内核数据架构 ...

随机推荐

  1. 【转载】最完美解决Nginx部署ThinkPHP项目的办法

    网上通用解决方法的配置如下: server { ... location / { index index.htm index.html index.php; #访问路径的文件不存在则重写URL转交给T ...

  2. 一般多项式曲线的最小二乘回归(Linear Regression)

    对于一般多项式: K为多项式最高项次,a为不确定的常数项,共k+1个; 有离散数据集对应,其方差: β为,方差函数S对β自变量第j个参数的梯度(偏导数): 当以上梯度为零时,S函数值最小,即: 中的每 ...

  3. linux下svn常用命令

    (如果是第一次提交文件,很可能会出现“svn:'.'不是工作副本”,即当前目录不是工作副本,这个时候需要用到import: eg:svn import . url) 1.将文件checkout到本地目 ...

  4. Unity将来时:IL2CPP是什么?

    作者:小玉链接:https://zhuanlan.zhihu.com/p/19972689来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. Unity3D 想必大家都不陌 ...

  5. pt_table_checksum对检查表的chunk大小的限制

    02-16T10:22:38 Skipping table xoxdb.tb_valuelog because on the master it would be checksummed in one ...

  6. <转>技术团队新官上任之基层篇

    发表于2013-09-04 17:17| 10455次阅读| 来源<程序员>| 35 条评论| 作者高博 <程序员>杂志2013年9月刊技术团队管理EMC高博CTO 摘要:从技 ...

  7. Install Hbase

    1. You should guarantee you have installed hadoop on your computers. 2. Download and uncompress the ...

  8. iOS开发流程总结

    本文由社区会员umyueyue分享 以下是会员umyueue总结的iOS开发流程以及学习中的资料分享. 流程:注册.开发.真机测试.发布以及上线. iPhone iOS 4从注册到app上线开发流程 ...

  9. angularjs 表单验证(不完整版)

    针对项目实践表单验证总结: angular 的 form表单验证:form内需要novalidate取消默认验证,用ng自己的验证,form的名字是非常必要的 栗子:以注册为栗子,下面是注册的部分: ...

  10. JavaScript 基础第七天(DOM的开始)

    一.引言 JavaScript的内容分为三个部分,这三个部分分别是ECMAScript.DOM.BOM三个部分组成.所谓ECMAScript就是JavaScript和核心基础语法,DOM是文档对象模型 ...