Symbian
Symbian OS Library

FAQ-0435 How do I do Memory Leak Testing - particularly where there is cached memory?

[Index][spacer] [Previous] [Next]



 

Classification: C++ Category: Debugging
Created: 11/11/99 Modified: 11/24/2001
Number: FAQ-0435
Platform: Not Applicable

Question:
EPOC applications must run forever, without memory leaks.

How do I test this?


Answer:
In debug mode, the application will verify that there are no memory leaks on exit, and cause a panic if there are.
However normal testing isn't likely to highlight the main cause of memory leaks, which is stack pointers to allocated memory being lost during a Leave. The most common cause of a Leave is being out of memory. So 'Alloc Heaven Testing', as we at Symbian call it, usually consists of faking out-of-memory (OOM) situations and checking that there are no leaks as a result. You can fake OOM using __UHEAP_SETFAIL (see the SDK), and reset it using __UHEAP_RESET.

The simplest approach to checking for memory leaks while doing Alloc Heaven Testing is to use the __UHEAP_MARK and __UHEAP_MARKEND macros. These verify that the stack state at MARKEND is the same as at MARK, and mean that any memory leaks are spotted immediately. These pairs of macros can also be nested - see the SDK.

So a typical test might look like


    __UHEAP_MARK; // Redundant extra check demonstrating macro nesting.
    for (TInt ii=1;;++ii)
      {
      __UHEAP_FAILNEXT(ii);
      __UHEAP_MARK;
      CMyClass* myObject = new(ELeave) CMyClass;
      TRAPD(err,myObject->ConstructL());
      delete myObject;
      __UHEAP_MARKEND;
      if (err==KErrNone)
      break;
      }
      __UHEAP_MARKEND;
      __UHEAP_RESET;
      Note that __UHEAP_MARKEND also checks the heap for consistency. Many of the EPOC examples insert a call to User::Heap().Check() after MARKEND - but this is redundant. Since the macros compile to nothing in the release build, you can leave them in released code (though in this example they're only in the test code).

      Dealing with Caching

      There's a problem if the any of the operations allocate memory which is - legitimately - not freed up when the objects are deleted. For example, the cleanup stack may need to allocate more memory while running. So normally we do the following before the test code:


        // reserve some space on the cleanup stack
        {for (TInt ii=0;ii<1000;++ii)
          CleanupStack::PushL(&ii);}CleanupStack::Pop(1000);
          You may be able to do the same with the other operations. For example, if CMyClass implements some kind of cache - or uses other objects that do - you should initially create and destroy a CMyObject before doing the OOM test, by adding the following code before the start:

            CMyClass* myObject = new(ELeave) CMyClass;
            TRAPD(err,myObject->ConstructL());

            ASSERT( err == 0 ); // Use __DEBUG_ASSERT( err==0, User::Invariant() ) for ER3,4
            delete myObject;
            Another approach, if this doesn't work, is simply to do the OOM testing using __UHEAP_SETFAIL and omit all the calls to __UHEAP_MARK and __UHEAP_MARKEND. During app exit, any side allocations should also be cleaned up, so this will find any real memory leaks. However this approach removes the direct connection between the __UHEAP_MARKEND and the code that leaks, so it can be more difficult to track down problems.

            See also Locating the cause of a memory leak.