VC中的一些调试技巧
2006-04-27 00:53
417 查看
毕业快一年,做了2个项目,都是在别人的代码上作开发,苦不堪言:bug实在是太多。这一年中有大半的时间是在改别人的bug,也积累了一些经验,和大家分享。我的方法大多数都来自《Windows程序调试》(英文名DebuggingWindowsPrograms)。那本书里讲了很多方法,我只挑对我自己帮助最大的:
1.调试内存破坏。
这种bug的表现就是不定时,不定地方的崩溃。这种bug我一共碰到2次,每一次都花了很长时间,尤其是第二次,花了大家三天时间。其原因是堆(heap)被破坏掉了。
我的方法是这样的:在可能出现问题的地方加上对堆的检查,用如下代码:
2.查找memoryleak
可以通过内存分配号来查找memoryleak,方法是这样的(我以前写的+msdn,就不翻译了):
#ifdef_DEBUG
#define_CRTDBG_MAP_ALLOC
#define_INC_MALLOC
#include<stdlib.h>
//customfunctionsdeclaration(ATL+BETAversionproblems)
extern"C"
{
void*__cdecl_alloca(size_t);
#definealloca_alloca
}
#endif
Asyoucansee,_CrtDumpMemoryLeaksgivesyoumuchmoreusefulinformationwhen_CRTDBG_MAP_ALLOCisdefined.Without_CRTDBG_MAP_ALLOCdefined,thedisplayshowsyou:
thememoryallocationnumber(insidethecurlybraces).
thetypeofblock(normal,client,orCRT).
thememorylocationinhexadecimalform.
thesizeoftheblockinbytes.
thecontentsofthefirst16bytes(alsoinhexadecimal).
Youcanrunyourprogramtwiceinthesameway,thenyoucanfindthatthememoryallocationnumberoftheleakedmemoryisalwaysthesame,soyoucanusethememoryallocationnumbertofindthememoryleak;directlytosay,youcanbreaktheprogrambymemoryallocationnumber.
ThebelowistakenfromMSDN(DetectingandIsolatingMemoryLeaksUsingMicrosoftVisualC++)
TheCRTlibrarycountsallmemoryblocksallocatedduringarunoftheprogram,includingmemoryallocatedbytheCRTlibraryitselforbyotherlibraries,suchasMFC.Therefore,anobjectwithallocationnumbernwillbethenthobjectallocatedinyourprogrambutmaynotbethenthobjectallocatedbyyourcode.(Inmostcases,itwillnotbe.)
Youcanusetheallocationnumbertosetabreakpointatthelocationwherememoryisallocated.Todothis,setalocationbreakpointnearthestartofyourprogram.Whenyourprogrambreaksatthatpoint,youcansetsuchamemoryallocationbreakpointfromtheQuickWatchdialogboxortheWatchwindow.IntheWatchwindow,forexample,typethefollowingexpressionintheNamecolumn:
Ifyouareusingthemultithreadeddynamic-linklibrary(DLL)versionoftheCRTlibrary(the/MDoption),youmustincludethecontextoperator,asshownhere:
Now,pressRETURN.ThedebuggerevaluatesthecallandplacestheresultintheValuecolumn.Thisvaluewillbe–1ifyouhavenotsetanybreakpointsonmemoryallocations.ReplacethevalueintheValuecolumnwiththeallocationnumberofthememoryallocationwhereyouwanttobreak—forexample,18tobreakattheallocationshownintheoutputearlier.
Afteryousetbreakpointsonthememoryallocationsinwhichyouareinterested,youcancontinuedebugging.Becarefultoruntheprogramunderthesameconditionsasthepreviousrunsotheallocationorderdoesnotchange.Whenyourprogrambreaksatthespecifiedmemoryallocation,youcanlookattheCallStackwindowandotherdebuggerinformationtodeterminetheconditionsunderwhichthememorywasallocated.Ifnecessary,youcancontinueexecutionoftheprogramfromthatpointtoseewhathappenstotheobjectandperhapsdeterminewhyitisnotproperlydeallocated.(SettingaDatabreakpointontheobjectmaybehelpful.)
Althoughitisusuallyeasiertosetmemoryallocationbreakpointsinthedebugger,youcansettheminyourcode,ifyouprefer.Tosetamemoryallocationbreakpointinyourcode,addalinelikethis(forthe18thmemoryallocation):
Asanalternative,youcanusethe_CrtSetBreakAllocfunction,whichhasthesameeffect:
AstoyourAPP,youmustrenamethefilemsvcrtd.dlltolettheAPPusethedllfileinthefolderSystem32.Youshouldadd
3.跨进程调试。
比如两个程序APP1和APP2,由APP1调起APP2,这时候你想调试APP2.可以这样做,在APP2的initinstance()中合适的地方加上一句ASSERT(FALSE);让APP2停下来,然后用VCAttach过去,就可以到APP2对应的cpp里去设断点了。
《Windows程序调试》还讲了很多方法:比如设高级断点,远程调试,map文件等等,都是非常有用的方法,我在这儿都列出来,未免太罗嗦了。对于原理方面的东西,希望大家多去看书和msdn.再就是大家一定要写出高质量的代码,多加一句检查,可能会省去别人三天的时间。
有不妥当的地方,希望大家指正。
1.调试内存破坏。
这种bug的表现就是不定时,不定地方的崩溃。这种bug我一共碰到2次,每一次都花了很长时间,尤其是第二次,花了大家三天时间。其原因是堆(heap)被破坏掉了。
我的方法是这样的:在可能出现问题的地方加上对堆的检查,用如下代码:
//Getthecurrentstateoftheflag
//andstoreitinatemporaryvariable
inttmpFlag=_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
//TurnOn(OR)-Keepfreedmemoryblocksinthe
//heap’slinkedlistandmarkthemasfreed
tmpFlag|=__CRTDBG_CHECK_ALWAYS_DF;
//Setthenewstatefortheflag
_CrtSetDbgFlag(tmpFlag);
int*nn=newint;
deletenn;
//TurnOff(AND)-prevent_CrtCheckMemoryfrom
//beingcalledateveryallocationrequest,Itwillcausemuchtime
tmpFlag&=~_CRTDBG_CHECK_ALWAYS_DF;
//Setthenewstatefortheflag
_CrtSetDbgFlag(tmpFlag);
如果之前堆已经坏掉了,那么程序(Debug版)就会在分配内存的地方中断,在这儿是[code]int*nn=newint;[/code]
第一次破坏堆的代码是这样:
typedefstructaa
{
inta;
}AA;
AAs ;
inti=0;
for(i=0;i<n;i++)
{
…
…
for(i=0;i<n;i++){…}
…
…
s[i].a=0;
}
内外都使用i做循环变量,就这样把堆破坏了。
[code]第二次的代码比较隐蔽,我先是使用map文件找到了崩溃的地方,但是一看是一个window的API,就放过了,后来还是再用上面的方法,又定位到那个API:GetFileAttributesEx(szFile,GetFileExInfoStandard,&attributes);[/code]
发现szFile这个参数有问题,是一个不合法的文件名,然后再调用这个API之前作文件名的合法检查,就没事了。呵呵,真是这个API干的,看来我们还是不能让Microsoft什么都做。[code][/code]
2.查找memoryleak
可以通过内存分配号来查找memoryleak,方法是这样的(我以前写的+msdn,就不翻译了):
YoucanseetheinformationbelowinyourVCoutputwindowiftheapphavememoryleaks[code][/code]
Detectedmemoryleaks!
Dumpingobjects->
{18}normalblockat0x00780E80,64byteslong.
[code]
Data:<>CDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCD[/code]
Objectdumpcomplete.
IfyoucannotseethedumpinformationinVC,youcanaddthecodetothefilecrtdbg.h:
#ifdef_DEBUG
#define_CRTDBG_MAP_ALLOC
#define_INC_MALLOC
#include<stdlib.h>
//customfunctionsdeclaration(ATL+BETAversionproblems)
extern"C"
{
void*__cdecl_alloca(size_t);
#definealloca_alloca
}
#endif
Asyoucansee,_CrtDumpMemoryLeaksgivesyoumuchmoreusefulinformationwhen_CRTDBG_MAP_ALLOCisdefined.Without_CRTDBG_MAP_ALLOCdefined,thedisplayshowsyou:
thememoryallocationnumber(insidethecurlybraces).
thetypeofblock(normal,client,orCRT).
thememorylocationinhexadecimalform.
thesizeoftheblockinbytes.
thecontentsofthefirst16bytes(alsoinhexadecimal).
Youcanrunyourprogramtwiceinthesameway,thenyoucanfindthatthememoryallocationnumberoftheleakedmemoryisalwaysthesame,soyoucanusethememoryallocationnumbertofindthememoryleak;directlytosay,youcanbreaktheprogrambymemoryallocationnumber.
ThebelowistakenfromMSDN(DetectingandIsolatingMemoryLeaksUsingMicrosoftVisualC++)
SettingaBreakpointonaMemoryAllocationNumber
Thefilenameandlinenumberinthememoryleakreporttellyouwhereleakedmemoryisallocated,butknowingwherethememoryisallocatedisnotalwayssufficienttoidentifytheproblem.Oftenanallocationwillbecalledmanytimesduringarunoftheprogram,butitmayleakmemoryonlyoncertaincalls.Toidentifytheproblem,youmustknownotonlywheretheleakedmemoryisallocatedbutalsotheconditionsunderwhichtheleakoccurs.Thepieceofinformationthatmakesitpossibleforyoutodothisisthememoryallocationnumber.Thisisthenumberthatappearsincurlybraces,afterthefilenameandlinenumberwhenthosearedisplayed.Forexample,inthefollowingoutput,“18”isthememoryallocationnumber.Itmeanstheleakedmemoryisthe18thblockofmemoryallocatedinyourprogram.Detectedmemoryleaks!
Dumpingobjects->
C:/PROGRAMFILES/VISUALSTUDIO/MyProjects/leaktest/leaktest.cpp(20):{18}
normalblockat0x00780E80,64byteslong.
[code]
Data:<>CDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCD[/code]
Objectdumpcomplete.
TheCRTlibrarycountsallmemoryblocksallocatedduringarunoftheprogram,includingmemoryallocatedbytheCRTlibraryitselforbyotherlibraries,suchasMFC.Therefore,anobjectwithallocationnumbernwillbethenthobjectallocatedinyourprogrambutmaynotbethenthobjectallocatedbyyourcode.(Inmostcases,itwillnotbe.)
Youcanusetheallocationnumbertosetabreakpointatthelocationwherememoryisallocated.Todothis,setalocationbreakpointnearthestartofyourprogram.Whenyourprogrambreaksatthatpoint,youcansetsuchamemoryallocationbreakpointfromtheQuickWatchdialogboxortheWatchwindow.IntheWatchwindow,forexample,typethefollowingexpressionintheNamecolumn:
_crtBreakAlloc
Ifyouareusingthemultithreadeddynamic-linklibrary(DLL)versionoftheCRTlibrary(the/MDoption),youmustincludethecontextoperator,asshownhere:
{,,msvcrtd.dll}_crtBreakAlloc
Now,pressRETURN.ThedebuggerevaluatesthecallandplacestheresultintheValuecolumn.Thisvaluewillbe–1ifyouhavenotsetanybreakpointsonmemoryallocations.ReplacethevalueintheValuecolumnwiththeallocationnumberofthememoryallocationwhereyouwanttobreak—forexample,18tobreakattheallocationshownintheoutputearlier.
Afteryousetbreakpointsonthememoryallocationsinwhichyouareinterested,youcancontinuedebugging.Becarefultoruntheprogramunderthesameconditionsasthepreviousrunsotheallocationorderdoesnotchange.Whenyourprogrambreaksatthespecifiedmemoryallocation,youcanlookattheCallStackwindowandotherdebuggerinformationtodeterminetheconditionsunderwhichthememorywasallocated.Ifnecessary,youcancontinueexecutionoftheprogramfromthatpointtoseewhathappenstotheobjectandperhapsdeterminewhyitisnotproperlydeallocated.(SettingaDatabreakpointontheobjectmaybehelpful.)
Althoughitisusuallyeasiertosetmemoryallocationbreakpointsinthedebugger,youcansettheminyourcode,ifyouprefer.Tosetamemoryallocationbreakpointinyourcode,addalinelikethis(forthe18thmemoryallocation):
_crtBreakAlloc=18;
Asanalternative,youcanusethe_CrtSetBreakAllocfunction,whichhasthesameeffect:
_CrtSetBreakAlloc(18);
AstoyourAPP,youmustrenamethefilemsvcrtd.dlltolettheAPPusethedllfileinthefolderSystem32.Youshouldadd
{,,msvcrtd.dll}_crtBreakAlloc
totheWatch.You’duseStepIntoandsetthebreakpoint.
3.跨进程调试。
比如两个程序APP1和APP2,由APP1调起APP2,这时候你想调试APP2.可以这样做,在APP2的initinstance()中合适的地方加上一句ASSERT(FALSE);让APP2停下来,然后用VCAttach过去,就可以到APP2对应的cpp里去设断点了。
《Windows程序调试》还讲了很多方法:比如设高级断点,远程调试,map文件等等,都是非常有用的方法,我在这儿都列出来,未免太罗嗦了。对于原理方面的东西,希望大家多去看书和msdn.再就是大家一定要写出高质量的代码,多加一句检查,可能会省去别人三天的时间。
有不妥当的地方,希望大家指正。
相关文章推荐
- 一些VC的快捷键以及调试方法技巧
- 一些VC的快捷键以及调试方法技巧
- 一些VC的快捷键以及调试方法技巧
- 一些VC的快捷键以及调试技巧
- 一些VC的快捷键以及调试方法技巧
- VC中的一些调试技巧
- 一些VC的快捷键以及调试技巧
- 一些VC的快捷键以及调试方法技巧
- 一些VC的快捷键以及调试技巧
- 一些VC的快捷键以及调试方法技巧
- 一些VC的快捷键以及调试方法技巧
- VC++一些开发心得与调试技巧
- 一些VC的快捷键以及调试方法技巧
- VC中的一些调试技巧
- 一些VC的快捷键以及调试方法技巧
- 一些VC的快捷键以及调试技巧
- 一些VC的快捷键以及调试技巧
- 一些VC的快捷键以及调试方法技巧
- 搜集整理一些VC调试技巧
- 一些VC的快捷键以及调试方法技巧