December 21, 2014
Hot Topics:

Optimizing Data Segment Usage

  • September 25, 2003
  • By Nancy Nicolaisen
  • Send Email »
  • More Articles »

There are a lot of things that you can do to improve your Win32 application's runtime memory use under CE. However, you can also reap some fairly impressive gains in memory efficiency simply by being aware of where the linker puts data in your program's executable.

An executable file basically has two kinds of things in it: executable code and data. On all of the Windows hosts, code is "pure," meaning that you can't modify it at runtime. For this reason, the part of a Windows executable file that contains the code is designated "read only," so it is of little concern to us here. The rest of the executable file is devoted to data, of which there are two kinds: read-only data, such as literal strings and constants; and read/write data, which is usually either data with global scope or data defined by using the static keyword.

Because access permissions are set on a page-by-page basis once the program is in memory, these data storage areas in your program have to be created in page-sized increments. At a minimum, your executable file contains one page for static ("read-only") data, and one page for read/write data. This means that there well may be some unused space in the data storage areas of your executable file, and you could profit by using it instead of making allocation requests.

On the other side of the coin, you may discover that one or the other of your data sections is just slightly larger than one page, which causes the allocation of a lot of unnecessary space. Moving things around a bit may shrink your data sections and get you in under that critical threshold.

So, how do you find out how your application file lays out the data sections?

Set the linker output option for generating a mapfile; this contains data section names, lengths, and base addresses.

Here's how to interpret the parts of the link map that show how your program's data is organized.

Figure 1: An Abbreviated Link Map

ExeFileMem

  Timestamp is 3bbcb82d (Thu Oct 04 13:27:41 2001)

  Preferred load address is 00010000

  Start         Length     Name         Class
  0001:00000000 00000c48H .text         CODE
  0002:00000000 00000054H .rdata        DATA
  0002:00000054 00000028H .idata$2      DATA
  0002:0000007c 00000014H .idata$3      DATA
  0002:00000090 00000088H .idata$4      DATA
  0002:00000118 0000023cH .idata$6      DATA
  0002:00000354 00000000H .edata        DATA
  0003:00000000 00000088H .idata$5      DATA
  0003:00000088 00000004H .CRT$XCA      DATA
  0003:0000008c 00000004H .CRT$XCZ      DATA
  0003:00000090 00000004H .CRT$XIA      DATA
  0003:00000094 00000004H .CRT$XIZ      DATA
  0003:00000098 00000004H .CRT$XPA      DATA
  0003:0000009c 00000004H .CRT$XPZ      DATA
  0003:000000a0 00000004H .CRT$XTA      DATA
  0003:000000a4 00000004H .CRT$XTZ      DATA
  0003:000000a8 00000010H .data         DATA
  0003:000000b8 00000810H .bss          DATA
  0004:00000000 00000104H .pdata        DATA
  0005:00000000 000001f0H .rsrc$01      DATA
  0005:000001f0 000005d4H .rsrc$02      DATA

First, let's look at the two places read-only data is stored, the .rdata section and the resource data sections, .rsrc$01 and rsrc$02.

Here are a few lines from the ExeFileMem example. Basically, it is a typical "Hello World" generated application, but with some data declarations added for the purposes of producing the mapfile above.

// Global Variables:
HINSTANCE     hInst;          // The current instance
HWND          hwndCB;         // The command bar handle

                              //make a large global allocation
int           iLargeIntArray[512];
                              //the const keyword means this
                              //datum is read-only
const int     iConstDataItem = 1;

Notice the last declaration, iConstDataItem. This variable is declared with the keyword, which makes it non modifiable.

Porting Tip: Non-modifiable data is placed in the program section .rdata.

We've seen (a lot) that memory allocation operations typically have a granularity of one page. To designate an item or group of items as "read only," they have to reside together in their own page(s), because that is the smallest increment on which we can set access permissions. Any datum that we declare with the const keyword has to end up in a read-only data section because that's the only way to ensure that it is protected from modification.

Now, examine the map file line that gives the length of the .rdata section:

Start         Length     Name         Class

0002:00000000 00000054H .rdata        DATA

The length of this section is 54h (84 decimal); however, when loaded, this section will consume an entire page of program memory. Yikes! We need to find some other non-modifiable data we can move to this page, or this space will be wasted.

The first possibility that springs to mind is string data, and most applications have a number of them, stored as resources. Resources have their own section in the executable file layout. Here are the map file lines that apply to them.

Start         Length     Name         Class

0005:00000000 000001f0H .rsrc$01      DATA
0005:000001f0 000005d4H .rsrc$02      DATA

There's a good reason not to move string data out of the resource files and into the static data area. CE provides us with a special version of the LoadString() function used to load string resources that allows you to read the string in place. Calling LoadString() like this returns a pointer to the string:

LPCTSTR pStringResource;

//if the last parameter is NULL, get back a pointer to a
//constant string
pStringResource = (LPCTSTR)LoadString( hInstance, 
                                       IDS_STRING,
                                       NULL );

You can use the string, but you can't write back to it. Always use this function to load string resources you don't intend to modify.

There are lots of other possibilities for moving data to the .rdata section, but leave string resources in the resource section so you can use the CE version of LoadString().





Page 1 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel