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.
|