This article a copied form a book (which I cant remembers its name nor author right now) and is NOT written by me. It explains how WINDOWS 95 allocates and manages its memory and explains why more then 32-MB of physical memory is insignificant to WINDOWS 95. WINDOWS 98 is a better memory management system. Also WINDOWS NT. {-----------------------------------------------------------------------------} Chapter 13 - Memory Management and File I/O Windows 95 requires the presence of an 386, 486 or PENTUIM microprocessor. These processors use 32-bit memory addressing and are thus capable of accessing 2^32 or 4,294,967,296 bytes (4 gigabytes or GB) of physical memory. Of course most users of Windows 95 don't come close to this limit. According to the Windows 95 carton the operating system requires only 4 megabytes of memory but 8 MB is recommended. These day 16 MB is considered to provide ample elbow room for the most purposes. Although the 386, 486 and PENTIUM microprocessors are still capable of using segmented memory addressing Windows 95 keeps the segment registers fixed and instead opts for a 32-bit flat addressing scheme. This means that addresses in Windows 95 application are stored as simple 32-bit values again allowing the access of 4 GB of memory. The 32-bit address used by Windows 95 application programs to access code and data are NOT the 32-bit physical addresses that the microprocessor uses to access physical memory. The addresses that the application uses are called "virtual" address. It is translated to a physical address throughout a "page table". Application program can usually ignore this process. (That's one of the reasons why operating systems were invented). Your program seems to sit in a 32-bit address space, and there is nothing strange or awkward you must to do to access this memory. However some of the Windows technical documentation refers to virtual addresses and page tables so it's helpful to have a good grasp of what's going on. The physical memory is divided into "pages" that are 4096 (4 KB) bytes in length. Thus each page begins at an address with the lowest 12 bits equaling to zero. A machine equipped with 8 megabytes of memory has 2048 pages. The Windows 95 operating system maintains a collection of page tables (which are themselves 4-KB pages) to translate virtual adresses to physical addresses. Every process under Windows 95 has its own "directory page", which is a allocation of up to 1024 32-bit entries stored contiguously. The physical address of the current directory page is stored in a microprocessor register called CR3, which is changed when WIndow 95 switches control between processes. The top 10 bits of a virtual address specifies one of the possible entries in this directory page. The top 20 bits of the entry in these directory page indicate a physical address of a page table (The bottom 12 bits of the physical address are set to zero). This references another page, which also has up to 1024 32-bit entries. The middle 10 of the virtual address references one of these entries. Again, the entry has 20-bit physical address. The bottom 12 bits of a virtual address point to a physical position within this page frame. I know it's confusing at first. Shown symbolically, you can represent a 32 bit virtual address (which is what an application works with) as a 10-bit directory page entry (d), a 10-bit page table entry (p), and a 12-bit offset (o): dddd-dddd-ddpp-pppp-pppp-oooo-oooo-oooo For each process the microprocessor stores a 20-bit value in the CR3 register (r for register): rrrr-rrrr-rrrr-rrrr-rrrr The starting physical address of the process's current directory page is: rrrr-rrrr-rrrr-rrr-rrrr-0000-0000-0000 Keep in mind that all pages are stored on 4-KB boundaries, so each page begins at an address with the bottom 12 bits equal to zero. The microprocessor first accesses the physical address: rrrr-rrrr-rrrr-rrrr-rrrr-ddd-ddd-dd00 This location contains another 20-bit value (t for table): tttt-tttt-tttt-tttt-tttt which indicates the starting physical address of of a page table: tttt-tttt-tttt-tttt-tttt-0000-0000-0000 The microprocessor then accesses a physical address of: tttt-tttt-tttt-tttt-tttt-pppp-pppp-pp00 Stored in this area is a 20-bit value of a page frame (f for frame): ffff-ffff-ffff-ffff The final 32-bit physical address is a combination of this page frame with the bottom 12 offset bits of the virtual address: ffff-ffff-ffff-ffff-oooo-oooo-oooo That's the physical address. We're all done. It may seem as if this is an extensively time consuming process for translating a virtual address to a physical address, but it's really not. The INTEL 386, 486 and PENTIUM microprocessors have an internal cache that can save these page tables right within the processor. The translation actually occurs very quickly without any significant performance hit. The double-paging gives each application theoretical limit if over one million 4-KB pages. The advantages to paging are enormous: First applications are insulated from each other. No Process can inadvertently (or maliciously) write over the code or data of another process, because it cannot even address the other process's memory without the proper CR3 value, and setting this value is only within the domain of the WINDOWS 95 KERNEL. Second, this paging mechanism solves one of the most basic problems in a multitasking environment, which is the consolidation of free memory. In a simpler addressing scheme, as multiple programs are executed and exited, memory can become fragmented. If memory is too fragmented, programs cannot run because they don't have enough contiguous memory, even if the amount of total free memory is entirely adequate. With paging, it is not necessary to consolidate free physical free memory because pages do not need to be contiguous. Everything is handled through the manipulation the page tables. The only waste really comes from the overhead of the page tables themselves and the 4-KB granularity of the pages. Third, there are extra bits on the 32-bit page-table entries aside form the 20 bit address. One indicates that the particular page has been accessed (this is called the "accessed" bit); another if the page has been written to (the "dirty" bit). WINDOWS 95 can use these bits to determinate if a page of memory can be swapped to a disk file to obtain more free physical memory. Another bit ("present") indicates if the page has been swapped out to disk and must be reloaded into memory. Another bit ("read/write") indicates if the page can be written to. This bit protects code from errant pointers. for example, if you include the following statement in a WINDOWS program: * (int) WinMain = 0; you will get a message box saying: "This program has performed an illegal operation and will be shut down." This bit does not prevent a program from compiling program source code and storing assembly language instructions in the memory to be executed, as we'll see. I have a few further notes about WINDOWS 95 memory management: Virtual addresses are 32-bit wide. Your program code and data (static, stack or allocated) will have addresses between 0x0000000 to 0x7FFFFFFF. WINDOWS 95 itself uses addresses from 0x8000000 to 0xFFFFFFFF, and if this is where you'll find the entries to the WINDOWS 95 dynamic libraries. The total amount of free memory is determinate by the amount of free physical memory and the area of the hard disk available for page swapping. As is usual with virtual memory management, WINDOWS 95 employs a least-recently-used (LRU) algorithm to determinate what pages to swap to disk; because code pages are non writable, they can simply be reloaded from the .EXE file or the dynamic library. Sometimes you'll see that a disk is being accessed when you move the mouse from client area of one program to the client area of another. Why is this? WINDOWS has to send mouse movement messages to the second application. If the program's code to process this message is not currently in memory, WINDOWS must reload simultaneously and not much memory, you will probably witness some "thrashing" (an inordinate amount of disk activity) as you move from program to program because WINDOWS is reloading previously discarded pages. Sometimes individual programs will suddenly slow down (or stop entirely) while WINDOWS performs swapping. Code pages can be shared among applications. This is particularly used for dynamic link libraries. Several programs running at the same time can use the same WINDOWS 95 functions without requiring that the same code be loaded into memory multiple times. Only one copy of the code is necessary. When you dynamically allocate memory, each block that you allocate does not get its own page. Successive allocations of small amounts of memory will be on the same physical page to the nearest 4-bit starting address. (That is, an allocation of one byte uses 16 bytes.) If a particular block is reallocated to a larger size, it may have to be physically moved in memory if something follows it on the page. Aside from the 4-kb granularity of pages, physical memory cannot become hopelessly fragmented because defragmantion involves only manipulation of the page tables. However, an application's virtual memory can become fragmented if a application allocates, reallocated, and frees a great many memory blocks. The 2-GB limit on application code and data is usually sufficient to avoid problems. It is much more likely that a program will run out of physical memory before encountering a limit on virtual memory. But it can happen, and if you have a program where this problem is conceivable, you may want to give serious thought to "movable" memory, which I'll discuss in this chapter. Finally, after all these preliminaries, my advice remains the same: use the C library functions whenever possible. You have a 32-bit address space. Use it and (of your application is cool enough) abuse the hell out of it. Brought to you by dgi: www.members.xoom.com/dgi_il dgi_il@hotmail.com