Windows Mobile Heaps from the Large Memory Area

I recently worked on a project porting a Windows desktop application to a Windows Mobile 5 device and a Windows Mobile 6.1 device. Both Windows Mobile 5 and Windows Mobile 6.x are based on Windows CE 5.0. In Windows CE 5.0 and previous versions, the memory management is quite different than Windows XP and Vista. This is documented quite well on MSDN and Doug Boling’s book “Programming Microsoft Windows CE .NET” (3rd Edition). His latest book titled “Programming Windows Embedded CE 6.0″ is the 4th edition addresses Windows CE 6.0 where Microsoft changed the memory management. Previous to Windows CE 6.0 applications are limited to 32 MB of usable virtual address space per process. I am not going to describe the memory management of Windows CE/Mobile devices as the following links provide complete information.

Windows CE .NET Advanced Memory Management
http://msdn.microsoft.com/en-us/library/ms836325.aspx

Effective Memory, Storage, and Power Management in Windows Mobile 5.0
http://msdn.microsoft.com/en-us/library/aa454885.aspx

Doug Boling’s Windows CE Blog
Windows Mobile 6.1 Memory Management Changes
http://bolingconsulting.com/blog/?p=25

Most applications are not hindered by the 32 MB virtual address space per process architecture in Windows CE/Mobile devices; however, the application that I was porting required a large amount of memory to hold information and I quickly exhausted the 32 MB address space of my process yet had ample memory on the device (128 MB). Fortunately, Windows CE/Mobile does provide a way for an application to tap into additional address space, and therefore, additional memory. In Windows CE/Mobile requested memory allocations that are greater than 2 MB are allocated from the large memory area (0x40000000-0x7E000000). So for my porting project I created another heap in the large memory area and allocated the memory as needed.

I wanted to improve on the implementation used in the project and develop a set of APIs that would allow the automatic management of heaps that would use the virtual address space of the large memory area. These APIs along with C++ classes would allow an application designer to take advantage of virtual address space of the large memory area without having to handle the maintenance.

I created APIs to allow the user to allocate memory, reallocate memory, free memory and compact the heap(s) located in the large memory area. In an embedded device memory can become fragmented quickly, compacting the heap(s) combine adjacent free blocks of memory and decommiting large free blocks of memory. I also created a CString derived class that allocates memory from the large memory area. The application I was porting also used container template classes in the Standard C++ library (std::vector, std::list, etc.), so I also created an allocator to be used with these templates.

The private class CWMHeap manages the heaps created in the large memory area. A CWMHeap object is created by the global variable ‘g_WMHeap’. When the WMHeapAlloc function is called and no heaps exist a heap is created and the memory is allocated from that heap. If one or more heaps already exist, an allocation request is made in the existing heaps prior to creating a new heap.

Let’s look at some code that uses the WMHeap APIs.

MyBuffers myBuffers; // vector to hold pointers to buffers
// Allocate 35 1MB buffers;
DWORD dwBufferSize = 1024 * 1024;
for (int nIndex = 0; nIndex < 35; ++nIndex)
{
    // Allocate a 1MB buffer from the Large Memory Area.
    char* pBuffer = reinterpret_cast<char*>(WMHeapAlloc(0, dwBufferSize));
    if (NULL != pBuffer)
    {
        // Fill the buffer.
        memset(pBuffer, 'A' + nIndex, dwBufferSize);

        // Save the buffer pointer onto the vector.
        myBuffers.push_back(pBuffer);
    }
    else
    {
        TCHAR szMsg[100];
        _stprintf(szMsg, _T("Error allocating memory at index %d."), nIndex);
        MessageBox(NULL, szMsg, _T("Error"), MB_OK);
    }
}

// Reallocate the 34th buffer, increasing its size by 256 bytes.
dwBufferSize += 256;
char* pBuffer = reinterpret_cast<char*>(WMHeapReAlloc(0, myBuffers.at(33), dwBufferSize));
if (NULL != pBuffer)
{
    // Save the new pointer (as it may have changed) into the vector.
    myBuffers.at(33) = pBuffer;

    // Fill the memory.
    char ch = 'A';
    for (DWORD dwIndex = 0; dwIndex < dwBufferSize; ++dwIndex)
    {
        pBuffer[dwIndex] = ch;
        if (++ch > 'Z')
            ch = 'A';
    }
}
else
{
    // Note: The original buffer is still valid.
    MessageBox(NULL, _T("Unable to reallocate memory."), _T("Error"), MB_OK);
}

// Free all memory allocated from the Large Memory Area.
for (MyBuffersIter iBuffer = myBuffers.begin();
(iBuffer != myBuffers.end());
++iBuffer)
{
    WMHeapFree(*iBuffer);
}
myBuffers.clear(); // erase all entries in the vector.

// Compact the heap(s).
WMHeapCompact();

The first part allocates 35 1MB buffers. This causes two additional heaps to be created since an individual heap can have a maximum size of 32 MB. You can see this by using the Visual Studio Remote Heap Walker tool. In the image below you can see the local heap at 0x18050000 and two additional heaps at 0x50000000 and 0x52000000 for the process.

The 34th buffer is increased by 256 bytes. This causes a new allocation to be made, the contents of the first buffer copied to the new buffer and then the original allocation is freed. This causes memory fragmentation and can be seen using the Remote Heap Walker tool that comes with Visual Studio. In the image below the right window contains a listing of the allocations in the heap at 0x52000000 (pre-realloc) and the left window contains a listing of the allocations in the heap (post-realloc). As you can see the allocation at 0x52200080 (the 34th buffer) has been freed and a new allocation at 0x524000A0 has been made.

After all of the buffers have been freed and the heaps are compacted, the heaps are destroyed since there are no allocations. This is shown in the image below; note that only the local heap (0x18050000) exists for the process.

The next snip of code demonstrates the use of the WMHeapAllocator template class. As elements are pushed onto the vector memory is allocated from one of the managed heaps using the WMHeap APIs.

// Define a vector type to hold a series of values of type 'short'.
// The vector uses memory from the Large Memory Area.
typedef std::vector< short, WMHeapAllocator< short > > MyShorts;
MyShorts myShorts1;     // vector to store values

myShorts1.push_back(1);
myShorts1.push_back(2);
myShorts1.push_back(3);
myShorts1.push_back(4);

MyShorts myShorts2;     // vector to store values

myShorts2.reserve(5);   // allocate memory for five entries
myShorts2.push_back(5);
myShorts2.push_back(6);
myShorts2.push_back(7);
myShorts2.push_back(8);
myShorts2.push_back(9);

Vectors in a Windows CE/Mobile device should be used with the knowledge that unless the memory is reserved prior to pushing elements onto the vector, memory fragmentation will occur. This is demonstrated in the code snip above. The myShorts1 vector will allocate memory for the first element when it is pushed onto the vector. When the second element is pushed onto the vector, the vector allocates a new block of memory to hold two elements, the first element is then copied to the new allocation and the original allocation is freed (allocation at 0x50000060 in the image below). This continues as elements are pushed onto the vector. By reserving the vector memory up front only one allocation is made (0x50000080 in the image below) and memory is not fragmented and the operation is quicker.

The next snip of code demonstrates the use of the CWMHeapString class. The CWMHeapString class is derived from CString and allocates its memory using the WMHeap APIs.

CWMHeapString myEmptyString;                // an empty string
CWMHeapString myHelloString(_T("HELLO"));   // from a C string literal
CWMHeapString myCopyString = myHelloString; // copy constructor
CWMHeapString myExpString(myHelloString     // string expression
    + _T(" ") + myCopyString);
CWMHeapString myCharString(_T('x'));        // = "x"
CWMHeapString myCharRepString(_T('x'), 6);  // = "xxxxxx"
VARIANT var;
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = ::SysAllocString(L"Coding is fun.");
CWMHeapString myVarString(var);             // = "Coding is fun."

// The following statement does not call the assignment operator.
// The compiler considers the following statement equivalent to
// CWMHeapString myString("Hello World")
CWMHeapString myString = _T("Hello World");

The private CWMHeap will manage a seperate heap for strings by creating a heap and attaching the heap to a CWin32Heap object and allowing an CAtlStringMgr object to manage the heap.

DWORD CWMHeap::CreateStringHeap()
{
    DWORD dwError = ERROR_SUCCESS;
    // In Windows Mobile 5.0 the maximum amount that can be committed at a
    // time is 32MB. If more than 32MB is needed multiple heaps will need to
    // be created.
    // http://msdn.microsoft.com/en-us/library/aa908768.aspx
    //
    // Create a heap with an initial size of 4K and a maximum size of 32MB.
    m_hStringHeap = ::CeHeapCreate(0, 0x00001000 /* 4K */, 0x02000000 /* 32MB */,
    CWMHeap::AllocMemory, CWMHeap::FreeMemory);
    if (NULL == m_hStringHeap)
    {
        dwError = GetLastError();
    }
    else
    {
        // Attach to the heap and allow CWin32Heap to take ownership.
        m_StringHeap.Attach(m_hStringHeap, TRUE);

        // Set the CString memory manager to use the heap.
        m_StringMgr.SetMemoryManager(&m_StringHeap);
    }

    return dwError;
}

For most applications the local heap of the process will suffice; however, for those applications that require allocations that would exceed the 32 MB virtual address space these APIs will allow your applications to create additional heaps that utilize the large memory area of the Windows CE virtual address space.

The complete source (Visual Studio 2008 solution) can be downloaded using the link below.

http://cid-e7e4366eac188131.office.live.com/self.aspx/Live Writer folder/WinMobileHeap.zip

About these ads
This entry was posted in Computers and Internet. Bookmark the permalink.

2 Responses to Windows Mobile Heaps from the Large Memory Area

  1. lewi says:

    hello, very good work! I was also searching how to circumvent the process heap limitation under wince5. now I am doing it as you propose! thanks man! a slitly other use of heap.compact() helped us to solve some heap fragmentation problems too. feel free to contact me ;-)

  2. jeni says:

    one sample mobile

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s