VC调试技巧

Visual C++ 的 C 运行时刻函数库标识模板
0xCD    已经分配的数据(alloCated
Data)
0xDD    已经释放的数据(Deleted Data)
0xFD   
被保护的数据(Fence Data)

Visual C++ 的 C 运行时刻函数库内存块类型标识符
_NORMAL_BLOCK   
由程序直接分配的内存
_CLIENT_BLOCK   
由程序直接分配的内存,可以通过内存调试函数对其拥有特殊控制权
_CRT_BLOCK      
由运行时刻函数库内部分配的内存
_FREE_BLOCK     
已经被释放,但是跟踪仍然被保留下来的内存,这在用户选择了调试堆的选项 _CRTDBG_DELAY_FREE_MEM_DF
以后会出现
_IGNORE_BLOCK    当使用 _CrtDbgFlag 关闭内存调试操作以后分配的内存

Visual C++ 的 C 运行时刻函数库提供的帮助调试内存错误的函数
_CrtCheckMemory 
检查每一个内存块的内部数据结构和守护(guard)字节,以测试其完整性。
_CrtIsValidHeapPointer
检验指定指针是否存在于本地堆中
_CrtIsValidPointer 检验给定内存范围对读写操作是否合法
_CrtIsMemoryBlock
检验给定内存范围是否位于本地堆当中,是否拥有例如 _NORMAL_BLOCK
这样的有效内存块类型标识符(该函数还可以被用以获得分配数目以及进行内存分配的源文件名和行号)

用于调试内存泄露的 Visual C++ 的 C 运行时刻函数库中的函数
_CrtSetBreakAlloc  
在给定的分配数目上分配断点,每一块被分配的内存都被指派一个连续的分配号。(查找特定的内存泄露十分有用)
_CrtDumpMemoryLeaks
判断内存泄露是否发生。如果发生则将本地堆中所有当前分配的内存按照用户可以阅读的方式进行内存映象转储。(在程序结束的时候检测内存泄露十分有用)
_CrtMemCheckPoint  
在 _CrtMemState 结构中产生一个本地堆的当前状态的快照
_CrtMemDifference  
比较两个堆中的断点,将不同之处保存在 _CrtMemState
结构中。如果不同则返真。(检测特殊区域代码的内存泄露十分有用)
_CrtMemDumpAllObjectsSince将从给定堆断点或者从程序开始分配的内存的所有信息按照用户可以阅读的方式进行内存映象转储
_CrtMemDumpStatistics
将信息按照用户可以阅读的方式进行内存映象转储到一个 _CrtMemState 结构中。(对于得到被使用的动态内存的全面观察信息来说十分有用)

用于一般内存调试的 Visual C++ 的 C
运行时刻函数库中的函数
_CrtSetDbgFlag     
控制内存调试函数的行为
_CrtSetAllocHook   
加裁在内存分配过程中的钩子函数。(对于检测内存使用状况或者模拟内存不足情况十分有用)
_CrtSetReportHook  
加裁进行定制报告处理的函数。
_CrtSetDumpClient  
加裁对用户进行内存映象转储的函数。
_CrtDoForAllClientObject 对于所有作为用户块进行分配的数据,调用指定的函数

ATL 内存调试
在 #include <AtlCom.h> 之前,定义控制预处理的常量
_ATL_DEBUG_INTERFACES,这样就可以对接口资源泄露进行跟踪(跟踪 AddRef 和 Release)
INTERFACE LEAK:
RefCount = 7, MaxRefCount = 10, {Allocation = 42}
CMyComClass -
Leak
然后在服务器初始化的时候对 CComModule 对象的 m_nIndexBreakAt 成员变量进行设置
#define
_ATL_DEBUG_INTERFACES

BOOL WINAPI DllMain(...)
{
    if (dwReason ==
DLL_PROCESS_ATTACH) {
       
...
        _Module.m_nIndexBreakAt = 42;
// Set breakpoint to find interface leak
   
}
    ...
}

使用调试堆
必须使用程序的调试版本,连接的是 C 运行时刻函数库的调试版本,必须定义 _DEBUG,这样调试堆版本的 new 和 delete
才会被调用。
调试堆选项
_CRTDBG_ALLOC_MEME_DF,启动堆分配检查
_CRTDBG_DELAY_FREE_MEM_DF,阻止内存被真正释放
_CRTDBG_CHECK_ALWAYS_DF,每次内存分配和释放都调用
_CrtCheckMemory
_CRTDBG_CHECK_CRT_DF,一般不使用
_CRTDBG_LEAK_CHECK_DF,在程序结束时调用
_CrtDumpMemoryLeaks
推荐总是使用 _CRTDBG_ALLOC_MEM_DF 和
_CRTDBG_LEAK_CHECK_DF,仅仅在调试内存错误时才用 _CRTDBG_CHECK_ALWAYS_DF 和
_CRTDBG_DELAY_FREE_MEM_DF,

显示内存泄露
#define _CRTDBG_MAP_ALLOC 在所有头文件之前,
在 cpp 文件中,加上
#ifdef
_DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] =
__FILE__;
#endif

查看 Windows 内存地址
Windows 进程一般放在 0x00400000 的地址,0x00400000 是所有版本的 Windows
能使用的最低地址,进程实例句柄的值总是和它的基地址相同,
所有未被初始化的自动变量都会设上 0xCCCCCCCC,

Windows 2000 的虚拟地址空间的使用
0x00030000 ~ 0x0012FFFF 线程栈
0x00130000 ~
0x003FFFFF 堆(有时堆位于此处)
0x00400000 ~ 0x005FFFFF 可执行代码
0x00600000 ~
0x0FFFFFFF 堆(有时堆位于此处)
0x10000000 ~ 0x5FFFFFFF App Dlls, Msvcrt.dll,
Mfc42.dll
0x77000000 ~ 0xFFFFFFFF Advapi32.dll,...

通过设置数据断点,在对 0xCDCDCDCD,0xCCCCCCCC,0xDDDDDDDD
等地址修改时,调试器会提醒你,写非合法数据
调试比较难的内存破坏问题时,可以试试 _CRTDBG_CHECK_ALWAYS_DF 和
_CRTDBG_DELAY_FREE_MEM_DF,

当类需要析构函数或者复制构造函数或者赋值操作符时,它同时需要这三个,否则可能导致内存破坏和泄露,

用分配号定位内存泄露
_CrtSetBreakAlloc(27)
Watch 窗口
{,,msvcrtd.dll}_CrtSetBreakAlloc(27)

使用内存检查点
void LeakyFunction()
{
    _CrtMemState
oldState, newState, stateDiff;
   
_CrtMemCheckPoint(&oldState);
    {
   
...
    }
   
_CrtMemCheckPoint(&newState);
    if
(_CrtMemeDifference(&stateDiff, &oldState, &newState))
{
       
_CrtMemDumpStatistics(&stateDiff);
       
_CrtMemDumpAllObjectsSince(&oldState);
    }
}
使用
_CRTDBG_DELAY_FREE_MEM_DF 调试堆选项防止 _CrtMemDumpAllObjectsSince 导出错误的结果

在删除图形设备接口对象前,一定确定它们没有被任何有效的设备上下文选中
在 Windows 2000
里发现资源泄露是最简单方法是运行性能监视工具,监视程序的私有空间和句柄数随时间的变化,如果私有空间或者句柄数据持续增长,就出现了内存泄露
函数的返回值是通过
EAX 传递的,

--------------------------------------------------------------------------------------------

函数运行时间
@CLK,d
@CLK,0

函数返回值
32位 - @EAX
64位 -
@EAX(低32位),@EDX(高32位)
大于64位,会在EAX中放入指向返回值指针,如返回一个 CRect, (CRect *) @EAX /
在内存窗口的Address栏中键入EAX查看

API 调用失败,键入@ERR可查看 GetLastError()的值, 翻译错误代码"@ERR,hr"

Windows自身会创建退出代码为 -1 的线程,如显示一通用对话框时,不用担心其返回为 -1,
关闭 GDI
的批处理功能,GdiSetBatchLimit(1)便于调试绘图代码;

画图代码闪烁的调试,
1.不适当的UpdateWindow调用,
2.调用InvalidateRect而不指定更新矩形,
3.调用InvalidateRect而将擦除背景参数不适当地设置为真,
4.不适当地使用CS_HREDRAW和CS_VREDRAW窗口风格,仅当客房区大小改变需要重画整个窗口时,才需要设置这两种风格。
如果窗口中的某些元素需要居中放置,这是必要的,

调试WM_MOUSEMOVE消息,大部分情况下,你希望在鼠标移动到窗口的特定位置或在特殊的环境下才发生中断,这时可以这样写
void
CMyWnd::OnMouseMove(UINT nFlags, CPoint point)
{
#ifdef _DEBUG
 
if (GetAsyncKeyState(VF_CONTROL) < 0) {
     int bogus
= 0;  // 可以在这里设置断点,仅当你按下Ctrl键时,才进入这里.
 
}
#endif
}
WM_LBUTTONDOWN 和 WM_LBUTTONUP 消息也是一个问题,因为在 WM_LBUTTONDOWN
消息处理函数中设置一个断点
很可能会导致 WM_LBUTTONUP
被调试器吸收.绕开这个问题的办法是在调试器中一直保持鼠标按下状态,只使用键盘控制调试器,
程序重新获得了输入焦点,你就可以释放鼠标按钮了。

使用 Spy++的 Log Messages 调试与消息有关的问题.

使用回调帮助调试代码,如调试工具提示时,使用 LPSTR_TEXTCALLBACK,

--------------------------------------------------------------------------------------------

某些变量应使用 volatile 避开编译器优化,使编译器产生的代码总是直接访问内存。
当前线程 ID, 在 Watch 窗口中输入
dw(@TIB+0x24)。

设置特定线程的断点,在关注的线程的 Watch 窗口中输入 @TIB 以确定线程的 TIB 地址,然后设置条件断点,@TIB ==
TIBAddress,TIBAddress是伪寄存器 @TIB 的值。
利用 TIB 的 pvArbitary 域设置了线程名称以后,可以在 Watch
窗口中输入 (PCHAR)(dw(@TIB+0x14))以显示当前线程的名称。
如果要单独调试某一线程,可以先在线程列表选择目标线程,再 SetFocus
这一线程,而后暂停所有其他线程,

时间: 2025-01-02 09:16:34

VC调试技巧的相关文章

VC 调试技术与异常(错误)处理 VC 调试技术与异常(错误)处理

调试技术与异常(错误)处理 (1)   转载自 52PK游戏论坛 跟踪与中间过程输出 也许一个开发人员一半以上的时间都是在面对错误,所以好的调试/查错方法(工具)会减轻我们工作的负担,也可以让枯燥的DEBUG过程得以缩短. VC开 发环境所提供的调试环境是很优秀的,我们可以运用单步运行,设置断点的方法来查找问题所在.但是这种跟踪是非常耗时的,所以我们需要采用一些策略来让我们 更容易的发现错误并对错误进行定位,所幸的是VC在这方面提供了强大的支持.在本节中我们先看看如何利用设置断点和利用TRACE

反调试技巧总结-原理和实现

标 题: [原创]反调试技巧总结-原理和实现(1)(2)(3)(4)(5)(6)......作 者: shellwolf时 间: 2008-08-10,22:40链 接: http://bbs.pediy.com/showthread.php?t=70470 反调试技巧总结-原理和实现-------------------------------------------------------------------------------------------------------2008

Visual Studio原生开发的10个调试技巧(一)

最近碰巧读了Ivan Shcherbakov写的一篇文章,<11个强大的Visual Studio调试小技巧>.这篇文章只介绍了一些有关Visual Studio的基本调试技巧,但是还有其他一些同样有用的技巧.我整理了一些Visual Studio(至少在VS 2008下)原生开发的调试技巧.(如果你是工作在托管代码下,调试器会有更多的特性,在CodeProject中有介绍它们的文章),下面是我的整理的一些技巧: 异常中断 | Break on Exception Watch窗口中的伪变量 |

asp.net调试技巧

一眨眼的功夫,自己已经学习asp.net的有一年的功夫了.虽然称不上什么大神,但是也有一点知识的积累.就写一片调试的入门文章给那些刚刚入门迷茫的童鞋们.希望你学习了我这篇文章能从迷茫的生活中找回编程的你. 对于程序员说永远也逃不了调试这个门槛.曾经记得有次,那是我还大一,学习的是c在vc下面,同学写了一段代码,就是计算每月的几日对应找出这 年的第几天.这个非常简单的问题我想谁都会有思路,但是我朋友代码写出来了,编译运行也都通过了,但偏偏就是得到的结果不对.我一看他的代码也没发现什么 问题,这个让

[转] Xcode 高级调试技巧

在苹果的官方文档中列出了我们在调试中能用到的一些命令,我们在这重点讲一些常用的命令 调试本地文件方法(Mac OS X):(lldb) target create "/Users/piaoyun/Desktop/xx.app/Contents/MacOS/xxxx" 远程调试方法: 设备端运行: 附加进程: ./debugserver *:1234 -a "YourAPPName" 直接启动进程: debugserver -x backboard *:1234 /p

Chrome 中的 JavaScript 断点设置和调试技巧

你是怎么调试 JavaScript 程序的?最原始的方法是用 alert() 在页面上打印内容,稍微改进一点的方法是用 console.log() 在 JavaScript 控制台上输出内容.嗯~,用这两种土办法确实解决了很多小型 JavaScript 脚本的调试问题.不过放着 Chrome 中功能越发强大的开发者工具不用实在太可惜了.本文主要介绍其中的 JavaScript 断点设置和调试功能,也就是其中的 Sources Panel(以前叫 Scripts).如果你精通 Eclipse 中的

一探前端开发中的JS调试技巧

前言:调试技巧,在任何一项技术研发中都可谓是必不可少的技能.掌握各种调试技巧,必定能在工作中起到事半功倍的效果.譬如,快速定位问题.降低故障概率.帮助分析逻辑错误等等.而在互联网前端开发越来越重要的今天,如何在前端开发中降低开发成本,提升工作效率,掌握前端开发调试技巧尤为重要. 本文将一一讲解各种前端JS调试技巧,也许你已经熟练掌握,那让我们一起来温习,也许有你没见过的方法,不妨一起来学习,也许你尚不知如何调试,赶紧趁此机会填补空白. 骨灰级调试大师Alert 那还是互联网刚刚起步的时代,网页前

js调试技巧 Firefox调试技巧汇总

Firebug入门指南        :  http://www.ruanyifeng.com/blog/2008/06/firebug_tutorial.html Firebug控制台详解: http://www.cnblogs.com/see7di/archive/2011/11/21/2257442.html    http://www.cnblogs.com/leejersey/archive/2012/11/27/2790998.html debugger: js中调用console写

5个Xcode开发调试技巧

转自Joywii的博客,原文:Four Tips for Debugging in XCode Like a Bro 1.Enable NSZombie Objects(开启僵尸对象) Enable NSZombie Objects可能是整个Xcode开发环境中最有用的调试技巧.这个技巧非常非常容易追踪到重复释放的问题.该技巧会以非常简洁的方式打印指出重复释放的类和该类的内存地址. 怎么开启僵尸对象呢?首先打开 Edit Scheme (或者通过热键?<),然后选择Diagnostics选项卡,