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

我们以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. 【java】:枚举小demo

    package com.jwis.study.enumeration; /** * @author lx * 枚举的一些方法 */ //⑴ enum Substar{tst1,tst2,ts3} pu ...

  2. Clone

    Clone: 构建一个对象的时候,是不是一定要调用构造函数! package com.edu.test; public class Zhenzhen implements Cloneable{ pub ...

  3. 模拟XShell的小项目

    不知道大家有没有用过XShell这款工具,这款工具通过windows可以远程操作处于开机状态的linux操作系统,也就是说把你的电脑和一台服务器连入网络,你通过输入服务器所在的IP地址建立一个会话就可 ...

  4. the fourth class

    6 居右 label加宽度,text-align:right 7 list copy: list1.concat(list1) 8 灵活运用addHandle,addEventListener 给in ...

  5. Scrum - BB项目日志

    这是第三个Scrum团队开发,也是我首次担任Scrum Master一职.所以需要掌握的流程还是很多,也会碰到各种问题,在此记录一下,希望对以后有所帮助. Day1: 开了一次kick-off mee ...

  6. Swift语法简介(二)闭包

    突然看到别人写的关于Block的帖子,让我突然有一种想写一篇关于闭包的帖子.在我的认知中,Swift中的闭包,就是Object-C中的Block--(或许我的认知太浅了).先上一个闭包的简单例子 le ...

  7. hdu 5543 Pick The Sticks(动态规划)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5543 题意:给你一根长为m的长木板和一些小木棒,每一根小木棒有它的长度和价值,这些小木棒要放在长木板上 ...

  8. .net之微信企业号开发(一) 所使用的环境与工具以及准备工作

    前言 一直以来,从事的是.net winform的编程,虽然对移动互联这块很感兴趣,但是由于现有的工作和移动互联之间隔的太远,也就没有时间和精力好好的去研究和实现.今年年初辞职了,刚好朋友那里希望建立 ...

  9. IOS的一些小技巧

    1.播放短声音 SystemSoundID shake_sound_male_id = ; NSString *thesoundFilePath = [[NSBundle mainBundle] pa ...

  10. Core Audio(二)

    用户模式音频组件 在windows vista中,core audio apis充当用户模式音频子系统的基础,core audio apis作为用户模式系统组件的一个thin layer,它用来将用户 ...