在Win32 程序中每个进程都占有4GB的虚拟地址空间,这4G的地址空间内部又被分为代码段,全局变量段堆段和栈段,栈内存由函数使用,用来存储函数内部的局部变量,而堆是由程序员自己申请与释放的,系统在管理堆内存的时候采用的双向链表的方式,接下来将通过调试代码来分析堆内存的管理。

堆内存的双向链表管理

下面是一段测试代码

#include <iostream>
using namespace std; int main()
{
int *p = NULL;
__int64 *q = NULL;
int *m = NULL; p = new int;
if (NULL == p)
{
return -1;
}
*p = 0x11223344; q = new __int64;
if (NULL == q)
{
return -1;
}
*q = 0x1122334455667788; m = new int;
if (NULL == m)
{
return -1;
}
*m = 0x11223344; delete p;
delete q;
delete m;
return 0;
}

我们对这段代码进行调试,当代码执行到delete p;位置的时候(此时还没有执行delete语句)查看变量的值如下:

p q m变量的地址比较接近,这三个指针变量本身保存在函数的栈中。从图中看存储这三个变量内存的地址好像不像栈结构,这是由于在高版本的VS中默认开启了地址随机化,所以这里看不出来这些地址的关系,但是如果在VC6里面可以很明显的看到它们在一个栈结构中。

我们将p, q, m这三者所指向的内存都减去 0x20 得到

p - 0x20 = 0x00035cc8 - 0x20 = 0x00035ca8
q - 0x20 = 0x00035d08 - 0x20 = 0x00035ce8
m - 0x20 = 0x00035d50 - 0x20 = 0x00035d30

在内存窗口中分别查看p - 0x20, q- 0x20, m- 0x20 位置的内存如下

通过观察发现p - 0x20处前8个字节存储了两个地址分别是 0x00035c38、0x00035ce8。是不是对0x00035ce8 这个地址感到很熟悉呢,它就是q - 0x20 处的地址,按照这个思路我们观察这些内存发现

内存地址 前四个字节 后四个字节
0x00035ca8 0x00035c38 0x00035ce8
0x00035ce8 0x00035ca8 0x00035d30
0x00035d30 0x00035ce8 0x00000000

看到这些地址有没有发现什么呢?没错,这个结构有两个指针域,第一个指针域指向前一个节点,后一个指针域指向后一个节点,这是一个典型的双向链表结构,你没有发现?没关系,我们将这个地址整理一下得到下面这个图表

既然知道了它的管理方式,那么接着往后执行delete语句,这个时候再看这些地址对应的内存中保存的值

内存地址 前四个字节 后四个字节
0x00035CA8 0x00035d70 0x000300c4
0x00035ce8 0x00035c38 0x00035d30
0x00035d30 0x00035ce8 0x00000000

系统已经改变了后面两个节点中next和pre指针域的内容,将p节点从双向链表中除去了。而这个时候仔细观察p节点中存储内容发现里面得值已经变为 0xfeee 了。

我们在delete的时候并没有传入对应的参数告知系统该回收多大的内存,那么它是怎么知道该如何回收内存的呢。我们回到之前的那个p - 0x20 内存的图上看,是不是在里面发现了一个0x00000004的值,其实这个值就是当前节点占了多少个字节,如果不相信,可以看看q- 0x20 和m - 0x20 内存处保存的值看看,在对应的偏移处是不是有 8和4。系统根据这个值来回收对应的内存。


最新文章

  1. HDU1075
  2. 22.编写一个类A,该类创建的对象可以调用方法showA输出小写的英文字母表。然后再编写一个A类的子类B,子类B创建的对象不仅可以调用方法showA输出小写的英文字母表,而且可以调用子类新增的方法showB输出大写的英文字母表。最后编写主类C,在主类的main方法 中测试类A与类B。
  3. 转:bwa的使用方法
  4. window.event对象详尽解析
  5. 解决Spring4 MVC请求json数据报406错误
  6. 【iHMI43 4.3寸液晶模块】demo例程(版本1.00)发布
  7. C#读取shapefile文件(不用AE)
  8. C++模板特化
  9. 从输入一个URL到页面呈现,网络上都发生了什么?
  10. window7 远程连接 拒绝访问
  11. Android学习----Android架构
  12. Activity间切换的动画应用
  13. select 通过表单提交获取select中的值
  14. CodeForces-747A
  15. MyCP -tx -xt 功能的Java实现
  16. 770. Basic Calculator IV
  17. 欢迎访问新博客(pfzheng.tech)
  18. 提升HTML5的性能体验系列之一 避免切页白屏
  19. VB按字节截取字符串
  20. redis 报错及解决

热门文章

  1. codis__使用注意事项
  2. dotnet core2常用命令
  3. php-elasticsearch scroll分页详解
  4. c语言-勒让德多项式求解+时间测定
  5. Linux安装Elasticsearch-head插件
  6. 高阶篇:6)设计评审Design reviews;
  7. HDU - 5306 剪枝的线段树
  8. 阿里云redisA迁移redisB迁移
  9. appium解决无法通过name属性识别元素org.openqa.selenium.InvalidSelectorException: Locator Strategy &#39;name&#39; is not supported for this session
  10. http请求全过程