Writing Memory Efficient CE Applications, Page 2
In part, the durability, and hence mobility, of CE devices derives from the fact that they have no moving parts ( disk drives, for example ). All storage is either in ROM ( Read Only Memory )or non-volatile RAM (Random Access memory ). ROM is used to store the operating system and any bundled applications a vendor distributes as part of the device.
RAM is divided into two regions: the object store, and program memory. The object store is functionally equivalent to the file system of a desktop computer. Files, application data, and third party executable code are stored here. All files in the object store are maintained in a special compressed format. This compression process isn't visible to you, the programmer, but it's one reason that CE programs appear to execute more slowly than desktop programs — everything, including executable code, must be uncompressed when you access it and recompressed when you store it. Users can adjust the proportions of memory devoted to the object store and to program memory.
Porting Tip: Writeable memory is divided into a persistent storage area, the object store, and an area in which code executes, program memory. Users can adjust the proportion of memory devoted to each of these areas.
All third party code and some ROM based code is stored in compressed format. Program memory is where code executes if it was stored in compressed form. This system is highly space efficient, because Windows CE uses demand paging to load pages of executables: The loader uncompresses requested pages, and brings them into program memory a page at a time ( page size is determined by device manufacturers, but in practice is either 1K or 4 K), as they are needed. Older pages are swapped out as the execution point moves past them and they are no longer needed ( a Least Recently Used algorithm determines which pages are swapped ).
Some ROM resident code is not stored in compressed format. Obviously, it would be extremely wasteful to compress and uncompress parts of the kernel and OS that are almost constantly in use. This type of code executes in place, that is, in ROM, using only small amounts of program memory for stack and heap space. This means that it doesn't incur the overhead of the compression cycle or the load process — providing a significant performance advantage and power savings, but at the cost of increased storage space.
Other less frequently used ROM resident executables and DLLs are stored in compressed format. This code is treated exactly the same as RAM resident compressed code. It is uncompressed and loaded on demand, executing RAM based program memory.
How CE Applications Allocate Memory
The Windows CE memory management API is sophisticated, but it is lean. It consists of three groups of API functions: the VirtualAlloc family, the HeapAlloc family and the LocalAlloc family. Don't use the C runtime functions to allocate memory on CE — this will cause unpredictable behavior.
Porting Tip: Eliminate all calls to calloc(), malloc() and alloc(). Replace these with the Windows CE memory allocation APIs that best suite your needs.
Basically, the size, duration, and consistency of your application's memory allocation will determine which type of allocation strategy you'll want to use. Our two goals in allocating memory under CE are to use memory as sparingly as possible, and when we are done with it, to make sure that it is made available to other processes as quickly as possible. Here are three important differences between the families of allocation functions:
- When they withdraw memory blocks from the allocation pool, giving your application exclusive access to them
- How much memory they actually remove from the allocation pool
- When they return the memory to the allocation pool after you free it
Let's look at the allocation APIs based on types of allocation scenarios.