Detecting Application Memory leaks in Unmanaged C++ with 4 lines of code:

来源:互联网 发布:郭艾伦大赛数据 编辑:程序博客网 时间:2024/05/24 16:14

We have customers who suspect memory leaks in our APIs.  Their only clues are that memory grows and that they are using one of our APIs.  One big problem is finding out if it’s their code or our API. Well, we need try doing a simple repro using our API – this gives us a better idea of what’s going on. However it’s not always clear if an API having the problem under or their code.  There is a simple technique to seeing if there is a leak in their code by adding a few lines of code.   

 

    Debugging Visual C++ - General debugging info

    http://msdn2.microsoft.com/en-us/library/k70yt3e2(vs.71).aspx

 

    Enabling Memory Leak Detection - this work, please try them

    http://msdn2.microsoft.com/en-us/library/e5ewb1h3(vs.71).aspx

 

Here is how it works:

 

1)     Add the following to the top of your code – this will cause debug versions of new and delete, etc to be used.

     #define CRTDBG_MAP_ALLOC  

     #include <stdlib.h>  

    #include <crtdbg.h>    

 

2)     Now at a place where you expect everything created to have been destroyed, add the line below in the code. 

      This line will print memory leak information to the output window:

   _CrtDumpMemoryLeaks();  // dump memory leaks to the output window

 

3)     Set a break point on _CrtDumpMemoryLeaks(); and run the code.

 

4)     Now step though _CrtDumpMemoryLeaks(); and you will get something like the following in the output window.  These are the items for which memory had been allocated and not yet released.  You might want to copy the output to notepad for future reference.

 

Detected memory leaks!

Dumping objects ->

{64} normal block at 0x00BE2DD8, 12 bytes long.

 Data: <            > C4 16 16 00 00 00 00 00 01 00 00 00

{59} normal block at 0x00BE2D48, 12 bytes long.

 Data: <|           > 7C FC 15 00 00 00 00 00 01 00 00 00

{54} normal block at 0x00BE2EB0, 2048 bytes long.

 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD

{53} normal block at 0x00BE2E68, 12 bytes long.

 Data: <|           > 7C 85 13 00 00 00 00 00 01 00 00 00

{47} normal block at 0x00BE2D00, 12 bytes long.

 Data: <            > AC 83 13 00 00 00 00 00 01 00 00 00

{46} normal block at 0x00BE2CB8, 12 bytes long.

 Data: <t           > 74 83 13 00 00 00 00 00 01 00 00 00

Object dump complete.

 

    Looking at the first entry, you will see:

   {64} normal block at 0x00BE2DD8, 12 bytes long.

        Data: <            > C4 16 16 00 00 00 00 00 01 00 00 00

        

            The “{64}” is the memory allocation occurrence. So, there were 63 memory allocations

            which already occurred.

            “0x00BE2DD8” is the memory address of the allocation.

The “Data: <            >” shows the first 12 bytes of data at that memory space – so if it’s a

string data, then you would see text.

“C4 16 16 00 00 00 00 00 01 00 00 00” is for those 12 bytes in hex.

 

So, at the point that the leak dump was done above, we know that some stuff had memory allocations but was not unallocated… so what does this give us?  The main key here is the memory allocation instance – like the {64} in the above example.  You can set a breakpoint at that memory allocation – below are two methods for doing this:

 

1)     Do it in code by adding a line setting a breakpoint at that allocation:

   _crtBreakAlloc = 64; // Break at the 64th memory allocation.

     Or

   _CrtSetBreakAlloc(64);  // Break at the 64th memory allocation.

 

2)     Do it in the Watch window:

Run the app in debug and add “_crtBreakAlloc” under the Name column. 

In the Value column, enter the allocation instance – in the example above, its 64.

Please note that the allocation instance seems to reset to -1, so you may need to reset it at times.

 

When you run the code, you will be prompted to break – do so.  You will see that you stopped at a line like the following in dbgheap.c:

           /* break into debugger at specific memory allocation */

        if (_crtBreakAlloc != -1L && lRequest == _crtBreakAlloc)

            _CrtDbgBreak();

 

From here, step-out until you get back to your source file – you will end-up at the line at which the memory allocation was done – so you know what was leaking now.  From here you just need to find out why it was not released.

 

Checking for leaks when you don’t have the code:

 

    UMDH

    How to Use Umdh.exe to Find Memory Leaks

    http://support.microsoft.com/kb/268343/EN-US/

 

What causes leaks?

 

... Ok, here are a few causes...

 

1)     If you create something with a New, you should release it.

In C++, you would have a “delete” for each “new”. In C++, never mix malloc and/or free with new/delete – mixing may cause a leak.  Also, malloc/free don’t fire the constructors or destructors. 

In VB.NET, you would set an object to “nothing” if it was created with a new.

In C# you would set an object to “null” if it was created with a new.

 

2)     If you open it, you should close it.

This goes for all things which can be opened.  If there is an “open” method, there is most likely a “close”.  Don’t rely on things to be closed when they fall out of scope – that’s sloppy.

 

3)     If you reference it, dereference it.

If you have reference objects, pointers, etc to stuff, you should dereference it properly.  Don’t assume that it won’t matter because of scope, etc.

 

So, set it to null, noting, etc.

 

4)     If its VC++/COM object, call ->Release() as needed.  An example of this would be to call on a bodypart to be sure it releases.

 

5)   Assuming destruction.

Magic does not always happen as expected; don’t assume that things will magically get cleaned-up by losing scope or closing something.  Add some code and walk through it with the debugger – be sure you get what you expect.

 

6)   .NET – COM Resurrection, GC.Collect, Marshal.ReleaseComObject

This is .NET magic… Com items created do not get destroyed automatically when dereferenced.  Were you assuming they did?  If a COM component is created and then dereferenced, it hangs around for a while unless you call ReleaseComObject on it.  If you don't get rid of it, .NET may re-use the object (COM Ressurection) - which in some cases may cause problems.

 

The Garbage Collector takes care of destruction at a time it deems it should - or is that true? Calling GC.Collect will force an application to do all garbage collection at one time- mass destruction - hmmm is that true.  Both are not really correct.  You can force collection on a particular item by calling ReleaseComObject if the object is COM based.  An example of this would be a CDOSYS bodypart for an attachment.  You should be sure to call System.Runtime.InteropServices.Marshal.ReleaseComObject(oBP); to force its release.  GC.Collect will tell garbage collection that managed objects can be collected... this does help, but is not a cure-all. You will find though that .NET will actually collect on managed objects some time later when the app ends or when when there is sufficeint memory pressure to do so (ie the memory needed).

 

7)   When deleting from an array, each pointer in that array must be individually deleted. After this is done, then the array can be deleted. Remember arrays are arrays of pointers.

 

8)   When you have an event which has a com object passed by value and not by reference, you will have a leak if you do not call  Marshal.ReleaseComObject() on that object.  This is true for com managed objects which wrap com objects.  An example of this is Outlook Object Model (OOM) code which passes an item by value to one of its events (such as onEvent_ItemSend()).

 

9) The instance item of a FOREACH loop needs to haveMarshal.ReleaseComObject() called on it if the underlaying object is COM.

 

10) If you use a for loop for looping through a collection which is COM based, you need to call Marshal.ReleaseComObject() on any objects which have references set to anything in that collection.  The same goes for using an enumerator. 

 


转自:http://blogs.msdn.com/b/webdav_101/archive/2008/03/31/detecting-application-memory-leaks-in-unmanaged-c-with-4-lines-of-code.aspx

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 嘴唇上长很多泡怎么办 嘴巴里长白色泡怎么办 做了漂唇起泡了怎么办 漂唇之后起泡了怎么办 漂唇后起了水泡怎么办 嘴唇起泡,弄破了怎么办 九个月的宝宝上火了怎么办 8岁儿童嘴唇起泡怎么办 宝宝嘴皮上火起泡了怎么办 上嘴唇起泡肿了怎么办 上嘴唇突然肿了怎么办? 醒来上嘴唇肿了怎么办 嘴巴突然肿了怎么办呢 下嘴唇肿起来了怎么办 上嘴唇肿了起泡怎么办 上火下嘴唇肿了怎么办 上火嘴唇都肿了怎么办 嘴唇起泡后肿了怎么办 嘴唇上有白点颗粒状怎么办 嘴唇缺了一块红怎么办 人得钩端螺旋体怎么办 脖子上有鸡皮肤怎么办 不结婚老了以后怎么办 丁克族老了怎么办知乎 2个月宝宝咳嗽怎么办 干活累的手疼怎么办 脸上长白色的癣怎么办 全身起红斑很痒怎么办 宝宝脖子红烂了怎么办 背上长红斑很痒怎么办 身上起风疙瘩很痒怎么办 身上起小包很痒怎么办 浑身起红包很痒怎么办 手太粗糙怎么办小窍门 小腿长疙瘩很痒怎么办 腿过敏起红疙瘩怎么办 肚子上起红疙瘩很痒怎么办 小蚂蚁咬了肿了怎么办 锦鲤鱼尾巴烂了怎么办 泰迪身上长白毛怎么办 鱼身上有红斑了怎么办