Previous Table of Contents Next


If you do not have access to the source code, you can try the following:

  Inform the manufacturer of the problem, and try to get them to fix it.
  Run the application at off-peak times by using the scheduler service.
  Start the application from the command line with the Start command at a lower priority. For example, start AppName /low, where AppName is the name of the application to execute.
  Add additional processors. This will only provide additional benefits if you have multiple threads/processes to execute. For the Microsoft BackOffice products, this can provide significant benefits because these applications are designed with multithreading/multiprocessing concepts.
  Upgrade the processor. Change from an 80486 to a Pentium, or from a Pentium to a Pentium Pro. Or, change from an Intel processor to a RISC processor.
  Upgrade the processor to one with a larger internal cache. For example, the Pentium Pro includes two versions of the CPU: one with an internal 256K cache and one with a 512K cache. Because the cache executes at the same speed as the internal processor, this can offer significant performance improvements.
  Upgrade the secondary system cache. This item is quite important when adding additional memory to the system. As you increase system memory, the cache has to map a larger address space into the same size cache. This can increase the cache miss ratio and degrade performance.

Finding Memory Bottlenecks

If you do nothing else to your system, adding additional memory will almost always increase system performance. This is because Windows NT Server will use this memory instead of virtual memory and decrease paging. It will also be used by the cache manager to cache all data accesses. This includes remote (i.e., network) and local resource access. Other applications can also benefit from this increased memory. For example, Microsoft SQL Server can use some of this memory for its data cache, procedure cache, and the temporary database.

Just like finding processor bottlenecks, you have to start with the big picture and then narrow down the search to a specific application to find the memory resource hog. A good starting point is to use the performance counters listed in Table 6.2 to see if you have a problem. If a problem is found, you can use the Process memory-related counters to see which application is the resource hog. Let’s step through an example to see how this operation works.

Table 6.2 Memory performance object counters.

Object Counter Instance Description
Memory Pages/Sec. N/A This item is the number of pages read from or written to disk to resolve memory references to pages that were not in physical memory at the time.
Memory Available Bytes N/A The amount of free virtual memory.
Memory Committed Bytes N/A The amount of memory that has been committed to use by the operating system as opposed to memory that has been merely reserved for use by the operating system.
Memory Page Faults/Sec. N/A The number of virtual memory page faults that occurred on the system because the physical page was not in the working set or main memory. A page may not need to be read from disk, if the page is available on the standby list or is in use by another process that shares the page and has it in its working set.
Memory Cache Faults/Sec. N/A The number of page faults that occur in the cache manager in reference to a memory page that is not in the cache.
Paging File % Usage Per Page File The amount of use of a specific page file.
Paging File % Usage Peak Per Page File The maximum use of a specific page file.

The first step in isolating the memory bottleneck is to load the Memory.PMW workspace file into the Performance Monitor. This workspace includes basic counters for the chart, alert, and report views. Once more, you want to obtain a baseline for an inactive system and then for your normally active system. To illustrate how a memory-intensive application would be displayed using the Performance Monitor, I wrote the application MemHog.EXE. The source code for MemHog is shown in Listing 6.3.

Listing 6.3 The MemHog sample application source code.

//------------------------------------------------------------------------------------
// THIS CODE AND INFORMATION IS PROVIDED “AS IS” WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
//
//   MemHog.C            Sample Application to demonstrate
//                       memory intensive application.
//
//
// Copyright (c) 1993-1997  Knowles Consulting. All rights Reserved.
//
//------------------------------------------------------------------------------------
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>

#define MAX_MEM_SIZE  1048576

int main (void)
    {
   HGLOBAL ptrMemBlock[100];
    int i;
   char chChar;

   // Allocates 100 1MB blocks of memory, populates the block with '*',
   // and then pauses for 30 seconds between allocations.
     for (i=0;i<100;i++)
       {
      ptrMemBlock[i] = GlobalAlloc(GPTR, MAX_MEM_SIZE);
       if (ptrMemBlock[i] != NULL)
          {
          memset(ptrMemBlock[i], '*', MAX_MEM_SIZE);
          if ((i%10) == 0)
             {
              Sleep(30000);
             }

          }
       else
          {
          break;
          }

       }

   // Displays number of memory blocks and total memory allocated,
   // then waits for the user to press a key.
   printf ("Allocated %d 1 MB memory blocks for a total \
of %d bytes.\r\n" , (i), (i * MAX_MEM_SIZE));
   printf(" Press any key to continue!\r\n" );
   chChar=getchar();

   // Frees allocated memory.
    for (i=0;i<=100;i++)
       {
       if (ptrMemBlock[i] != NULL)
          {
           GlobalFree(ptrMemBlock[i]);
          }

       }

   return (FALSE);
   }


Previous Table of Contents Next