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

我们以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. Android安全之Intent Scheme Url攻击

    0X01 前言 Intent scheme url是一种用于在web页面中启动终端app activity的特殊URL,在针对intent scheme URL攻击大爆发之前,很多android的浏览 ...

  2. maven使用

    Maven是一个项目管理和构建自动化工具.但是对于我们程序员来说,我们最关心的是它的项目构建功能,它定义了项目开发的几个标准步骤:编译,发布,单元测试及部署以帮助项目开发 最简单的时候场景是,在pom ...

  3. 安装完ODAC,出现ORA-12560:TNS:协议适配器错误 12541 无监听程序的解决

    进入系统环境变量设置,查看Path路径,发现D:\oracle\product\11.2.0\client_1等路径放到了oracle11g数据库路径前面,将新加入的路径置后即可解决ORA-12560 ...

  4. Bomb

    Description The counter-terrorists found a time bomb in the dust. But this time the terrorists impro ...

  5. js 有用的代码

    1. 如何创建嵌套的过滤器: //允许你减少集合中的匹配元素的过滤器, //只剩下那些与给定的选择器匹配的部分.在这种情况下, //查询删除了任何没(:not)有(:has) //包含class为“s ...

  6. python subprocess 自动运行实验室程序

    import threading, os, subprocess, time exec_path = "/home/xhz/gems/ruby/amd...../bin/tester.exe ...

  7. 小JAVA大世界之万年历

    import java.util.Scanner; public class Calendar { public static void main(String[] args) { // 万年历 in ...

  8. 数位DP

    题意:(hdu 4734) 我们定义十进制数x的权值为f(x) = a(n)*2^(n-1)+a(n-1)*2(n-2)+...a(2)*2+a(1)*1,a(i)表示十进制数x中第i位的数字. 题目 ...

  9. WINCE 获取智能设备唯一编号

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  10. SpringMVC常用注解實例詳解1:@Controller,@RequestMapping,@RequestParam,@PathVariable

    我的開發環境 框架:        springmvc+spring+freemarker 開發工具: springsource-tool-suite-2.9.0 JDK版本: 1.6.0_29 to ...