下面的是一个简单的测试程序,基本包括了所有的变量类型,包括静态的,常量的,全局的,本地的,还有new出来的

#include <iostream>

using namespace  std;

const char* global_const_string = "hello world";
int global_int = ;
static int global_static_int = ;
int main()
{
static int local_static_int = ;
int local_int = ;
int* pValue = new int(); cout << global_const_string << global_int
<< global_static_int << local_static_int
<< local_int << *pValue;
delete pValue;
system("pause");
return ;
}

下面我们依次分析每个变量所属的存储区域:

我们直接用WinDbg以源码的方式调试我们的测试程序consoleTest.exe.
首先我们分析下consoleTest.exe模块的起始地址及内部数据节的分布情况, 通过!address命令:

*   400000   401000     1000 MEM_IMAGE   MEM_COMMIT  PAGE_READONLY                      Image "ConsoleTest.exe"
|-  401000   41d000    1c000 MEM_IMAGE   MEM_COMMIT  PAGE_EXECUTE_READ                  Image "ConsoleTest.exe"
|-  41d000   422000     5000 MEM_IMAGE   MEM_COMMIT  PAGE_READONLY                      Image "ConsoleTest.exe"
|-  422000   426000     4000 MEM_IMAGE   MEM_COMMIT  PAGE_WRITECOPY                     Image "ConsoleTest.exe"
|-  426000   427000     1000 MEM_IMAGE   MEM_COMMIT  PAGE_READONLY                      Image "ConsoleTest.exe"

可以看到consoleTest.exe模块在内存中的起始地址是0x400000, 接下来可以通过!dh 0x400000分析它内部的数据节分布, 并且最终我们可以得出如下结论:
地址 400000 - 401000 : PE文件头,属性是只读
地址 401000 - 41d000 : .text, 属性是只读可执行,表示代码节
地址 41d000 -  422000 : .rdata, 属性是只读, 表示只读数据
地址 422000 -  426000 : .data, 属性是写入时拷贝,表示可读写数据
地址 426000 - 427000 : .rsrc, 属性是只读,表示资源节

通过!address -f:stack命令我们可以看到:

0:000> !address -f:stack
 
  BaseAddr EndAddr+1 RgnSize     Type       State                 Protect             Usage
-------------------------------------------------------------------------------------------
   40000   13d000    fd000 MEM_PRIVATE MEM_RESERVE                                    Stack [8b0.1d0; ~0]
  13d000   13e000     1000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE|PAGE_GUARD          Stack [8b0.1d0; ~0]
  13e000   140000     2000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE                     Stack [8b0.1d0; ~0]
可以看到我们主线程的堆栈起始地址是: 13e000 - 140000

接下来我们首先分析所有全局变量的存储区域, 通过x consoletest!global*命令,让调试器列出所有在consoletest模块中global开头的调试符号:

0:000> x consoletest!global*
00422000 ConsoleTest!global_const_string = 0x0041d1dc "hello world"
00422004 ConsoleTest!global_int = 0n20
00422008 ConsoleTest!global_static_int = 0n30
004238a0 ConsoleTest!global_locale = 0x00000000
通过分析我们可以看到我们的3个全局变量global_const_string, global_int, global_static_int全都分布在422000 - 426000之间的.data可读写数据节中。
而global_const_string所指向的内容

0x0041d1dc "hello world"

则分布在41d000 -  422000 之间的.rdata只读数据节中,这个结论也符合我们平时关于全局变量存储区域的理解。

下面我们再尝试分析局部变量的存储区域,再main函数内部cout的地方设置断点,然后让程序运行到此, 然后输入dv /t /i /v命令查看所有局部变量, 可以看到

0:000> dv /t /i /v
prv local  0042200c int local_static_int = 0n100
prv local  0013ff70 int local_int = 0n200
prv local  0013ff74 int * pValue = 0x02248ff8

我们可以看到local_static_int也分布在422000 - 426000之间的.data可读写数据节中, 而local_int和pValue则都存储在13e000 - 140000之间的堆栈区域上。

而指针pValue所指向的地址0x02248ff8我们可以通过!address 0x02248ff8命令来分析, 结果是:

0:000> !address 0x02248ff8

Usage:                  Heap
Allocation Base:        021d0000
Base Address:           02248000
End Address:            02249000
Region Size:            00001000
Type:                   00020000    MEM_PRIVATE
State:                  00001000    MEM_COMMIT
Protect:                00000004    PAGE_READWRITE
More info:              !heap -p 0x21d1000
More info:              !heap -p -a 0x2248ff8

可以看到地址0x02248ff8是在堆(heap)上面。

通过上面的分析,我们验证了平时C++书上关于各种类型变量存储区域的假设,简单来说就是全局变量和静态变量会被编译到可执行文件的数据节(分只读和可读写)中, 非静态的局部变量则分配在堆栈(stack)上,而new(malloc)出来的内存则分配在堆(heap)上。

转自 http://www.cppblog.com/weiym/archive/2012/09/20/191429.html

利用Windbg深入理解变量的存储模型的更多相关文章

  1. 深入理解Java虚拟机内存模型

    前言 本文中部分内容引用至<深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)>第12章,如果有兴趣可自行深入阅读,文末放有书籍PDF版本连接. 一.物理机中的并发 物理机遇到的并 ...

  2. 利用 V8 深入理解 JavaScript 设计

    JavaScript 代码运行 以大家开发常用的 chrome 浏览器或 Node 举例,我们的 JavaScript 代码是通过 V8 运行的.但 V8 是怎么执行代码的呢?当我们输入 const ...

  3. 并发编程学习笔记之Java存储模型(十三)

    概述 Java存储模型(JMM),安全发布.规约,同步策略等等的安全性得益于JMM,在你理解了为什么这些机制会如此工作后,可以更容易有效地使用它们. 1. 什么是存储模型,要它何用. 如果缺少同步,就 ...

  4. Bitcask存储模型

    ----<大规模分布式存储系统:原理解析与架构实战>读书笔记 近期一直在分析OceanBase的源代码,恰巧碰到了OceanBase的核心开发人员的新作<大规模分布式存储系统:原理解 ...

  5. Prometheus存储模型分析

    Prometheus是时下最为流行的开源监控解决方案,我们可以很轻松地以Prometheus为核心快速构建一套包含监控指标的抓取,存储,查询以及告警的完整监控系统.单个的Prometheus实例就能实 ...

  6. SQLite剖析之存储模型

    前言 SQLite作为嵌入式数据库,通常针对的应用的数据量相对于DBMS的数据量小.所以它的存储模型设计得非常简单,总的来说,SQLite把一个数据文件分成若干大小相等的页面,然后以B树的形式来组织这 ...

  7. Bitcask 存储模型

    Bitcask 存储模型 Bitcask 是一个日志型.基于hash表结构的key-value存储模型,以Bitcask为存储模型的K-V系统有 Riak和 beansdb新版本. 日志型数据存储 何 ...

  8. C++变量的存储类别与作用域

    总结一下C++中变量的存储类别以及变量的作用域. (1)标示符的存储类别决定了标示符在内存中存在的时间(我们可以理解标示符就是确定一个变量的符号,也就是我们所说的变量名) 二:存储类别 (1)静态存储 ...

  9. SQLite入门与分析(八)---存储模型(1)

    写在前面:SQLite作为嵌入式数据库,通常针对的应用的数据量相对于通常DBMS的数据量是较小的.所以它的存储模型设计得非常简单,总的来说,SQLite把一个数据文件分成若干大小相等的页面,然后以B树 ...

随机推荐

  1. When you want to give up, remember why you started.

    When you want to give up, remember why you started.当你想要放弃的时候,请记住当初你为何而开始.

  2. 带你零基础入门redis【二】

    本篇文章介绍redis如何设置开机自启动以及如何在java中应用 一.设置redis开机自启 1.修改redis配置 [root@VM_6_102_centos ~]# vim /usr/local/ ...

  3. arcgis jsapi接口入门系列(9):可以同时显示多个的地图popup

    jsapi有提供popup功能,但缺点很多,例如地图上只能同时显示一个popup,popup内容有限制等 本文提供另一个方法,原理不用jsapi,在地图外用一个普通的div放在地图上面,再监听地图的鼠 ...

  4. ssh免密登录配置方法

    方法一 1.#ssh-keygen -t rsa 在客户端生成密钥对 把公钥拷贝给要登录的目标主机, 目标主机上将这个公钥加入到授权列表 #cat id_rsa.pub >> author ...

  5. 使用nodejs消费SAP Cloud for Customer上的Web service

    Jerry在公众号文章C4C和微信集成系列教程里曾经使用nodejs去消费C4C提供的标准webservice. 看一个具体例子:C4C里Individual Customers可以维护Social ...

  6. line-block,white-space,overflow

    line-block:设置行间的距离(行高),只能控制块级元素,span这样的行内元素无法控制,并且当块级元素 中包含span的时候设置line-block会使span的自适应高度小于块级元素的高度, ...

  7. 多线程程序设计-Thread的一些方法

    run():是程序中会和会和其他线程“同时”执行的部分.   wait():使得当前线程进入等待状态,等待的线程不会主动进入到线程队列中排队等待cpu资源,必须由其他线程调用notify()方法通知它 ...

  8. Sublime +Markdown+OmniMarkupPreviewer 搭建实时预览的markdown编辑器

    浏览器实时预览 <meta http-equiv="refresh" content="0.1"> auto save 的配置 {"aut ...

  9. Bootstrap历练实例:动画的进度条

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  10. 【期望dp】bzoj4832: [Lydsy1704月赛]抵制克苏恩

    这个题面怎么这么歧义…… Description 小Q同学现在沉迷炉石传说不能自拔.他发现一张名为克苏恩的牌很不公平.如果你不玩炉石传说,不必担心,小Q 同学会告诉你所有相关的细节.炉石传说是这样的一 ...