To access the contents, click the chapter and section titles.
Fast Track Visual C++ 6.0 Programming
(Publisher: John Wiley & Sons, Inc.)
Author(s): Steve Holzner
ISBN: 0471312908
Publication Date: 09/01/98
Chapter 7 32-Bit Memory Handling
In the old days of DOS, memory was restricted to 1MB, and of that 1MB, only 640K was usable. When Windows came along, the earliest versions still ran in 1MB. Eventually, that limit began to fall. As processors improved, Windows 3.1 was able to access up to 16MB, but when users started running several programs at the same time, even 16MB wasnt enough. With the introduction of 32-bit WindowsWindows 95the operating system could address 4GB, or 4,294,967,296 bytes. Thats enough to keep us going for a long time (in fact, you can only use 2GB4MB in Windows 95 and 98, but thats still quite a lot).
In this chapter, we present an overview of memory and then go to work allocating virtual memory, scanning all of memory to see whats there, and learning how to share memory between two running processes. Putting all this into action will expose us to a tremendous amount of memory power.
Overview of Memory
With 32 bits, pointers to memory can now range from 0x00000000 to 0xFFFFFFFF. In fact, each individual process gets a 4GB address space, though its hard to imagine a computer today with that much physical memory; instead, computers use virtual memory. Virtual memory is the memory that can spill over to disk when needed, and is swapped back into real memory (RAM) when needed.
Where Is the Windows Operating System?
The actual Windows operating system and DLLs are stored in very high memory, and though it is possible to overwrite them by mistake in Windows 95 and 98, you cant do that in Windows NT, which is one reason NT is more robust.
Lets take a look at memory, section by section, in Windows 95 and 98. The very bottom 64K of memory, from 0x00000000 to 0x00000FFF is reserved for NULL pointers. This region is taboo: If a pointer points to this region, Windows assumes its invalid and issues a NULL pointer error.
All the memory from the very bottom up to the end of the first 4MB is reserved for the systemlargely to maintain compatibility with Win16 programs, which place a lot of system code thereso our programs are actually loaded at the address 0x00400000. We have all the space from there to 0x7FFFFFFF with which to work. Above that region (starting at 0x80000000) is the Windows system itself.
Starting at 0x80000000 are the system DLLs (like USER.DLL); that section of memory goes up to 0xBFFFFFFF. Right after that location, starting at 0xC0000000 and continuing to the top of memory 0xFFFFFFFF, is where the operating system is, along with the virtual device drivers.
The following is a graphical overview of how memory is set up:
--------------------------------------
|0xFFFFFFFF |
| |
| Operating system |
| Virtual device drivers |
| |
|0xC0000000 |
|-------------------------------------- |
|0xBFFFFFFF |
| |
| WIN32 DLLs |
| |
| |
|0x80000000 |
|-------------------------------------- |
|0x7FFFFFFF |
| |
| User programs |
| |
| |
|0x00400000 |
|-------------------------------------- |
|0x003FFFFF |
| |
| 16-bit Windows (compatibility) |
| |
| |
|0x00001000 |
|-------------------------------------- |
|0x00000FFF |
| |
| NULL pointer assignments |
| 16-bit Windows (compatibility) |
| |
|0x00000000 |
--------------------------------------
Not all this memory is in your machine; often, Windows sends memory out to disk as virtual memory. Windows keeps a paging file on disk for just this purpose, and memory is divided into pages to make memory handling easier (the page size in Windows 95 and 98 is 4K).
Now that weve had an overview of memory, we look at some of the functions Visual C++ provides for us to work with when handling memory.
Powerful Memory Functions
The GetSystemInfo() function is a good place to start. This function fills a structure of type SYSTEM_INFO, which includes the minimum and maximum application addresses and the page size as shown in the following example:
typedef struct _SYSTEM_INFO { // sinf
union {
DWORD dwOemId;
struct {
WORD wProcessorArchitecture;
WORD wReserved;
};
};
DWORD dwPageSize;
LPVOID lpMinimumApplicationAddress;
LPVOID lpMaximumApplicationAddress;
DWORD dwActiveProcessorMask;
DWORD dwNumberOfProcessors;
DWORD dwProcessorType;
DWORD dwAllocationGranularity;
WORD wProcessorLevel;
WORD wProcessorRevision;
} SYSTEM_INFO;
The powerful VirtualQuery() function lets us take a look at a specific region of memory. Using this function, we can find the base address of an allocated region of memory as well as the size of the region. This and other information are stored in a structure of type MEMORY_BASIC_INFORMATION, which looks like this:
typedef struct _MEMORY_BASIC_INFORMATION { // mbi
PVOID BaseAddress; // base address of region
PVOID AllocationBase; // allocation base address
DWORD AllocationProtect; // initial access protection
DWORD RegionSize; // size, in bytes, of region
DWORD State; // committed, reserved, free
DWORD Protect; // current access protection
DWORD Type; // type of pages
} MEMORY_BASIC_INFORMATION;
typedef MEMORY_BASIC_INFORMATION *PMEMORY_BASIC_INFORMATION;
|