SmartHeap


SmartHeap Technical specification

Trademark notice

Table of contents

Overview

SmartHeap's version architecture

Portability

Debugging and error detection features

Summary of SmartHeap functions

SmartHeap reliability confirmation test suites

Here's what users are saying about SmartHeap

Partial list of SmartHeap customers

© 1993-1997 MicroQuill Software Publishing, Inc.


Overview

Industry leaders at WordPerfect, Lotus, Sybase, Hewlett Packard, Symantec, Microsoft, Informix, Knowledgeware, Intersolv, Xerox, Traveling Software, and many others know memory management can affect an application's performance and reliability more than any other factor. These companies and many others rely on SmartHeap for their memory manager. Why? Because SmartHeap is the fastest, most portable, and most reliable allocator available. In addition, SmartHeap includes complete heap error detection facilities.

Speed

In C and C++ applications running on virtual memory systems, malloc and operator new affect performance more than any other factor. SmartHeap's proprietary algorithms deliver unparalleled malloc/new performance in Windows, UNIX (Sun, HP, etc.), OS/2, NT, Extended DOS, and Macintosh. Benchmarks show SmartHeap is 3X to 100X+ faster. You can achieve even better results if you use SmartHeap's malloc/new to automatically route allocations smaller than a size that you specify to an extremely fast fixed-size allocator. SmartHeap also provides multiple memory pools, which improve locality and further eliminate fragmentation.

Error detection

SmartHeap doesn't stop with blazingly fast performance. It also provides the most complete heap error detection available. Memory bugs are typically the most insidious, spurious, and damaging bugs an application faces. Because SmartHeap controls and manages the heap, it can detect bugs other add-on debugging tools miss. In addition to providing better error detection, SmartHeap uses its knowledge of the heap to report unsurpassed detail about the cause of each error. Bugs that SmartHeap detects include leakage, memory overwrites, double-freeing, wild pointers, invalid parameters, out of memory, references to previously freed memory, and so on.

Portability

In addition to outstanding speed and complete error detection, today's memory manager must be easily portable. SmartHeap ships as a binary linkable library for DOS, Windows, NT, Mac, OS/2, UNIX, etc. Each version provides an identical API, but is specifically optimized for that particular environment. Finally, SmartHeap's malloc and new are strictly ANSI compliant, so you don't have to code to a proprietary API to realize the benefits of SmartHeap.

Reliability

Because SmartHeap is a runtime library product, it must deliver absolutely bullet-proof reliability. To ensure the ultimate in error-free operation, we built a certification tester which calls each of the SmartHeap APIs hundreds of thousands of times. This tester actually includes more lines of code than SmartHeap and was designed to comprehensively test all possible conditions SmartHeap might face, thus proving that all of the bugs are out.

The bottom line? We guarantee that SmartHeap is faster, more reliable, more portable, and more complete in its heap error detection than ANY memory manager you're using -- or your money back.


Return to the Table of contents.


SmartHeap's version architecture

SmartHeap is a faster malloc/new library because its underlying algorithms are superior to those used in compiler-supplied libraries.

The problem: heap management is harder than you think

At first glance, writing a malloc/new library appears to be a very simple task; all the library has to do is allocate and free a few blocks. However, building a library that can handle a random mix of thousands or millions of allocations and frees of objects from one byte to megabytes in size, while running on a virtual memory, pre-emptively multi-tasking and multi-threading operating system, is not so easy. At least not if you also want the library to be fast and efficient in all conditions.

Applications must manage large numbers of objects

Today's applications, especially those written in C++, tend to be more memory intensive than ever before, often allocating, freeing, and referencing hundreds of thousands, or even millions, of small objects. Their allocation patterns are random, with calls to new interspersed with calls to delete. As a result, the heap quickly evolves into a fragmented, chaotic jumble.

This fragmentation, in turn, causes many commercial allocators to "hit the wall" - the performance of the allocator degrades exponentially as the heap size grows or when the allocator operates in virtual memory, rather than physical memory, conditions.

Large-footprint operating systems compete with your application for precious RAM

32-bit virtual memory operating systems provide the advantage of a huge address space. However, these operating systems themselves are huge, at least relative to the typical RAM configuration. As a result, they compete with your application for precious RAM and force your application's heap to swap far more frequently.

Windows 95, for example, has a footprint of some 14 MB - several times the size of Microsoft's suggested 4 MB minimum memory configuration.) Its sheer size relative to typically available physical memory guarantees that your application's heap will always be at least partially non-resident, so each call to allocate, free, or even reference memory is likely to invoke agonizingly slow disk hits. Windows NT and UNIX systems run on machines with more memory, but their respective footprints are also larger, as are the apps that run on them. As a result, the identical competition for memory and associated performance degradation occurs.

Pre-emptive multi-tasking and multi-threading operating systems increase swapping frequency

Pre-emptive multi-tasking in Win95, NT, OS/2, and UNIX further degrades performance. For example, your application (or one of its threads) may be in the middle of traversing a data structure when the operating system turns the processor over to another application or another thread. When your application (or that thread) gets its next slice of processor time, its data will often have been swapped to disk.

Multiple threads exacerbate the problem still further. In multi-threaded environments, objects are normally serialized so that only one thread can be active in the heap at a time. This makes the heap a real bottleneck for multi-threaded applications and affects performance:


Return to the Table of contents.


The solution: one allocator, three algorithms

Producing an allocator that's fast and efficient for objects of all sizes is not so easy. The algorithms that work best for allocating and freeing small objects don't work as well on large objects, and vice versa. SmartHeap solves this problem by implementing three distinct algorithms, one for small objects, one for medium-sized objects, and one for large objects. You don't have to change your code at all; you simply call new or malloc, just like before, and SmartHeap automatically uses the appropriate algorithm for the specified object size. Moreover, each SmartHeap algorithm scales well to very large heap sizes and is efficient in both physical and virtual memory conditions. (See the benchmark graphs later in this section.)

Allocating small objects (under 256 bytes)

The speed-space tradeoff of fixed-size allocators

If you've studied memory management, you know that a fixed-size allocator will always be faster than a variable-size allocator (2-10X faster, if not more, depending on heap-size). Fixed-size allocators reduce memory management to simple free-list management, which is extremely fast. Rather than searching the heap for the best fit, the fixed-size allocator can simply pick the head off the free list.

You also know that the vast percentage of objects allocated by C++ apps are for things like fixed-size structures and classes--objects that tend to be smaller than 256 bytes. If you could only find a way to get fixed-size allocation performance for all of these objects, you could get an immediate performance boost.

The tradeoff has always been that fixed-size allocators waste much more memory unless all objects are the same size. And when you're dealing with an entire heap, you're going to run across a wide spectrum of block sizes. Therefore, if you want to use a fixed-size allocator, you have to tediously analyze your code to find out how many objects you have of each size, create multiple fixed-size "pools" (mini-heaps) which correspond to where the object sizes congregate, and finally change your source to specifically call these specific fixed-size allocators. All this analysis and recoding takes time and precludes you from using an off-the-shelf malloc/new lib.

Alternatively, you could choose a single fixed-size allocator that handles all objects below a certain size and routes all others to a variable-size allocator. But this technique, which SmartHeap used in the 2.x release, isn't optimum either. No matter where you draw the line, any object smaller than the chosen size wastes memory. For example, if you route all objects up to 32 bytes long to a fixed-size allocator, every object smaller than 32 bytes wastes 32 - object size bytes of memory. This waste causes the heap to grow unnecessarily large. So you end up choosing a fixed-size level so small that only a few objects use the much faster fixed-size allocator, and overall performance improvement is negligible.

SmartHeap's fixed size allocator is fast and memory-efficient

To get around the speed versus waste tradeoff common to fixed-size allocators, SmartHeap dynamically establishes a separate fixed-size pool for each object size up to 255 bytes. You get 255 allocators without touching your code! For example, when your code first calls malloc or new to create a 32-byte object, SmartHeap automatically creates a 32-byte fixed-size pool and then allocates this object from it. All subsequent 32-byte objects are also allocated from this pool. The pools SmartHeap uses internally for these small allocations are very low-overhead, and free storage is shared between all the different sizes. So SmartHeap doesn't have the problem common to other fixed-size allocators of wasting reserved memory that is dedicated to each individual pool.

This technique delivers the performance of a fixed-size allocator and because every object maps perfectly to its own fixed-size allocator, the per-object overhead of the SmartHeap small-object allocator is only a single byte for Win 16, Win 32, and OS/2. (It's five bytes for UNIX and Mac platforms.) In comparison, Visual C++ 4.0 incurs 16 bytes of overhead for every object allocated, an amount that is often larger than the actual objects being allocated. UNIX allocators incur from 8 to 16 bytes per object, depending on the vendor.

Allocating medium-sized objects (256 bytes to 64K)

The fixed-size allocator that SmartHeap uses for objects smaller than 256 bytes isn't appropriate for larger blocks. While small blocks commonly hold thousands of repeat instances of fixed-size structures and classes, larger blocks commonly hold variable-size objects such as arrays and buffers which are rarely reused. Tying up memory to maintain a fixed-size pool for an object size that is rarely repeated causes the heap size to grow (and stay) unnecessarily large. Hence, for objects larger than 256 bytes but smaller than the operating system page size or system allocator granularity, SmartHeap uses a very efficient variable-size allocation algorithm.

The perils of locality of reference when allocating

The problem with conventional variable-size algorithms is that they effectively treat the heap as one large region, maintaining a single free list that spans the entire heap. Over time, as objects are continually allocated and freed, the free list ultimately degenerates into a random path of pages in the heap. This causes the allocator to jump from page to page as it traverses the free list, which it must do on every call to malloc/new and sometimes even on every call to free/delete. The heap in these conventional implementations exhibits poor page locality: data that is referenced consecutively (in this case, the heap free list) isn't stored in the same page of the heap.

The free list's lack of data locality wouldn't be a big problem if each free block were always large enough to satisfy each subsequent allocation request and if the heap were always entirely resident in physical memory. However, the same cycle of allocating and freeing that randomizes the free list also fragments the heap. This causes an ever-shrinking average block size, which, in turn, lessens the likelihood that "the next" free block in the list will be large enough to fulfill the current request. Moreover, as discussed above, most applications don't run purely in physical memory. As a result, a call to malloc or new often touches multiple pages while looking for a free block large enough for the object, and some of these touches invoke performance-killing disk hits. When a heap is fragmented and in tight memory conditions, a single allocation call can take a second or more as the allocator thrashes while traversing the free list.

The malloc and new implementations in all the compiler-supplied runtime libraries in DOS, Win16, OS/2, and the Mac, plus Borland's Win32 allocator, all use the conventional algorithm described above.

Most UNIX allocators and Microsoft's Win32 allocator improve on this by storing the free list and associated header information in a memory area separate from the blocks of data. Because the heap headers are smaller (usually eight bytes each) than the actual data, the free list can be stored more compactly, so data locality improves and swapping is reduced.

However, separating the free list from the data still doesn't eliminate swapping. For large heaps, the free list continues to span a large number of pages, so traversing it can still touch multiple pages. In addition, for heaps with a small median object size (common in C++), very little space is actually saved because the objects themselves take up very little space. So the free list turns out to be only marginally smaller, and substantial swapping still occurs.

Locality of reference also affects deallocation performance

Locality of reference is not just an issue when allocating memory; it is equally important when freeing memory. To minimize fragmentation, most allocators "coalesce," or merge adjacent free blocks to create a single larger space. To determine whether adjacent blocks are free, and thus could be merged, some allocators traverse the entire free list during calls to free. As a result, the same consequences of free list locality apply.

SmartHeap's unique page table algorithm maintains better locality of reference and reduces swapping when allocating memory

For medium size objects, SmartHeap uses a much smarter algorithm that virtually eliminates swapping while traversing the free-list. While other allocators treat the heap effectively as one large region, SmartHeap divides the heap into discrete pages that correspond with (and are perfectly aligned with) the pages of the underlying operating system virtual memory manager. And, also like the operating system, SmartHeap maintains a compact page table that keeps track of all of the pages in the heap.

For each page in the heap, SmartHeap's page table stores the size of the largest free block in that page. This page table is much smaller than the compiler allocator's free list because the page table has just one entry per page, rather than one entry per free block in the heap. Rather than searching one long list of free blocks (and touching many pages in the process), SmartHeap quickly scans its much smaller page table for a page that it knows has space for the current allocation request. SmartHeap's actual free list is contained inside each page -- since the free list doesn't reference any other pages, only a single heap page is referenced during a SmartHeap allocation. With this technique, SmartHeap virtually eliminates swapping during allocation calls.

Allocation speed is one clear benefit of SmartHeap's page-based allocation algorithm, but there is a more subtle benefit that can have an even greater impact on your application's overall performance.

We mentioned earlier how the free list in traditional allocators follows a random path through the heap. A consequence of this is that each object that your application creates will lie on a random page within the heap. SmartHeap, on the other hand, with its page-centric free list, always tries to allocate consecutive objects from the same page. The result is that the data referenced by your application has better locality. Applications often reference (and free) memory in the same pattern in which they allocate it. For example, elements successively inserted into a list will be allocated and referenced in the order of the list links. Therefore, referencing this data will involve accessing fewer pages, which further minimizes swapping.

SmartHeap's coalescing algorithms eliminate free list traversing when deallocating memory

As we mentioned above, many compiler allocators traverse the free list on every free to determine whether or not adjacent blocks are free, and thus can be merged. As a result, deallocation performance degrades more as the heap size (and thus the free list size) grows.

SmartHeap, on the other hand, doesn't rely on the free list at all to determine if adjacent blocks are free. Instead, it maintains special bits that indicate whether the adjacent blocks are free in the block headers for each object.. With each free/delete, SmartHeap checks this local header information and immediately coalesces any adjacent free blocks. This technique is constant time; it is not affected by the size of the heap. As a result, on all but the most modestly size heaps, SmartHeap is often orders of magnitude faster when freeing memory than compiler allocators.

Allocating large objects (over 64K)

On most platforms, very large objects are best managed by the operating system. Heap implementations such as Visual C++ 2.0 that include very large objects in the normal heap end up wasting memory and causing excessive fragmentation. By not returning memory to the operating system, the allocator hoards large amounts of memory in the application's heap. Moreover, when small objects are allocated in the space formerly occupied by a large object, the heap becomes fragmented, making it necessary to obtain yet more memory from the operating system when another large object is allocated.

SmartHeap solves these problems by treating large objects - those larger than the system page size and system allocator granularity - separately from either small or medium-sized objects. On platforms such as NT that provide an efficient large-object allocator, SmartHeap passes large object allocation requests directly to the OS. On other operating systems, such as Unix, that don't provide an efficient heap for large objects, SmartHeap implements its own large object allocator.

You can control the threshold between "medium" and "large" with a SmartHeap API. The default value is different on each platform, but is generally between 4K and 64K.

Other cool features in SmartHeap

Use SmartHeap's multiple pools on a data usage basis to achieve performance gains when referencing data

As we discussed above, SmartHeap automatically and transparently uses multiple memory pools for objects smaller than 256 bytes. In addition, you can explicitly create additional pools to further improve the performance of your application with minimal coding effort. (To allocate from a particular pool, you simply override the definition of new for a given class.)

Multiple pools let you partition your data (regardless of the size range of the objects) into discrete "mini-heaps". This has a number of benefits:

Shared memory

Shared Memory in Win32

In Windows NT and Windows 95, each 32-bit process has its own separate address space. To allow sharing of memory between processes, Microsoft's Win32 API provides memory-mapped files. Beginning in version 3.1, SmartHeap supports Windows 95 and Windows NT shared memory. SmartHeap uses memory mapped files to implement shared memory pools. All of the SmartHeap allocation APIs that accept a memory pool parameter support Win32 shared memory.

Because SmartHeap allocation APIs return direct pointers to memory, SmartHeap requires shared memory pools to be mapped to the same address in each process. In Windows 95, this is not a problem since shared memory is always mapped to the same address in each process. NT, however, does not guarantee that shared memory is mapped to the same address in each process. To solve this problem, SmartHeap includes the API MemPoolInitNamedSharedEx. This API lets you specify the address at which a shared memory pool should be mapped and/or an array of process IDs (pids) that will access the shared pool. If you specify a non-NULL value for pids, SmartHeap will search the address space of each of these processes to find a suitable address that is available in all of the processes. If you specify address as NULL, SmartHeap chooses a random address in the upper half of the application address space for NT, or a random address in the shared memory address space for Win95. This minimizes the chance of collisions with other shared pools or VirtualAlloc objects (which are normally allocated from the beginning of the address space).

If all of the processes that will share a memory pool are running at the time you create the memory pool, you can have SmartHeap find an address automatically by specifying pidCount and pids parameters. In this case, the shared pool will be mapped into each process's address space before the MemPoolInitNamedSharedEx call returns. If there is no address space region of suitable size available in every process, MemPoolInitNamedSharedEx will fail (this would be very unusual considering that each process has 2 GB of address space).

Win32's memory mapped files have a granularity of 4K: there's no heap API for allocating smaller blocks of shared memory. SmartHeap includes a malloc-like API to efficiently allocate small blocks (as small as 4 bytes) of memory and a free-like API to free individual small blocks. SmartHeap also provides overloaded operators new and delete for shared memory in C++. These APIs let you create and destroy sharable data structures of any kind, including those that contain pointers.

This ability to allocate very small blocks and to map memory-mapped files at the same address in each process make SmartHeap extremely useful when porting 16-bit code to Windows 95 or Windows NT.

Note: To guarantee that a set of processes will be able to successfully share a memory pool in NT, you must use the DLL version of SmartHeap.

Shared memory for other platforms

Beginning in version 3.0, SmartHeap supports UNIX shared memory. SmartHeap uses the shared memory and semaphore facilities of the standard InterProcess Communication (IPC) package to implement shared memory pools. You can use all of the SmartHeap allocation and de-allocation APIs with shared memory pools. In debug SmartHeap, shared memory pools fully support all of the same debugging facilities as private memory pools.

SmartHeap supports OS/2 shared memory. In SmartHeap for OS/2, you can allocate either named or unnamed shared memory pools. As with all other SmartHeap platforms with shared memory support, you can use all the SmartHeap allocation and de-allocation APIs, and debugging facilities are fully supported.

SmartHeap also supports shared memory in 16-bit Windows.

See the Getting Started and Programmer's Guide for platform-specific details of the SmartHeap shared implementation on your platform.

SmartHeap's handle-based allocator gives you speed and space

If you need a handle-based allocator, SmartHeap implements double-indirection handles. The memory is moveable, so fragmentation is eliminated. However you can access the memory very efficiently by de-referencing the handle as a pointer, which eliminates a performance-degrading function call. The handle-based allocator gives you both great performance and little waste in a feature that was previously available only on the Macintosh. In addition, for applications that use the Mac memory API, SmartHeap provides an emulation of the Mac memory API with an implementation that is much faster than the native Mac API.


Return to the Table of contents.


Benchmarks: blazingly fast performance

How important is malloc/free speed?

Consider a typical application, which spends 40% of its total execution time on managing memory and takes 10 minutes to run. The table below shows how a faster memory management library affects this application.

                     then malloc/new    the app          and the 
If malloc/new is     takes this         takes this       entire app is 
this much faster...  much time...       much time...     this much faster
-------------------------------------------------------------------------
no change (1X)         4.00 minutes     10.00 minutes           0%
1.5X                   3.60 minutes      9.60 minutes           4%
2X                     2.00 minutes      8.00 minutes          20%
4X                     1.00 minutes      7.00 minutes          30%
10X                    0.40 minutes      6.40 minutes          36%
100X                   0.04 minutes      6.04 minutes          39.6%

Note that even a 4X improvement in malloc can result in a 30% overall application performance improvement -- and remember that SmartHeap is generally a minimum of 4X faster than other commercial allocators and requires just a relink to implement.

Benchmark descriptions

The benchmark graphs on the following pages compare SmartHeap to compiler malloc/new libraries for various versions of Windows.

Note We also have benchmarks for the Macintosh, OS/2, SunOS, and HP 7xx. For more information, please call us at 206-402-9400 or email us at info@microquill.com.

Our benchmark test program randomly calls operators new and delete (in a ratio of 3:1) to create objects that randomly vary in size from 8 to 128 bytes until the heap reaches the specified size. The program then deletes all of the objects.

Note Applications that initially allocate all of their memory and do little or no subsequent allocation will not see substantial performance improvements because traditional new implementations are fast when allocating into a totally empty heap.


Return to the Table of contents.


Benchmark graphs

Windows NT benchmark test graph

Windows 95 benchmark test graph

Windows for Workgroups version 3.11 benchmark test graph

OS/2 Warp benchmark test graph

Power Mac benchmark test graph


Return to the Table of contents.


Portability

SmartHeap provides portability to a broad set of platforms from a single, ANSI C compliant source code base. We support compilers from Microsoft, Borland, IBM, Watcom, Metaware, SUN, HP, Symantec/Zortech, and others.

Platform-specific binary versions that are ready to be quickly and easily linked directly into an application are available for DOS, Extended DOS, Macintosh, Windows, NT/Win32s, OS/2, Unixware, SunOS, Sun Solaris, IBM AIX, HP-UX, SGI, and other platforms. Source code licenses are also available for all of these platforms and include the necessary .mak files for specific platforms.

To maximize performance and efficiency, we isolated all platform dependencies into a single module of SmartHeap. This module is carefully tuned for each platform using manifest constants to control such architecture-sensitive variables as alignment, system page size, pointer size, and integer size. The following examples illustrate how SmartHeap is carefully tuned for each platform:

You can also readily compile SmartHeap on platforms and operating systems for which MicroQuill has not yet provided integration. Please contact MicroQuill for pricing and support details.


Return to the Table of contents.


Debugging and error detection features

In addition to incredible runtime performance, SmartHeap provides the most complete heap error detection available. Because SmartHeap "owns" the heap, it not only detects more errors, but provides greater detail about each error than that provided by other "add-on" memory debuggers.

As SmartHeap's debugging version allocates each block, it keeps track of the following information:

The SmartHeap debug library provides three levels of error detection, from simple to very exhaustive. dbgMemSetSafetyLevel controls how error checking SmartHeap performs. The three "safety levels" are:

Information that SmartHeap includes in error reports

When SmartHeap detects an error, the following information is included in the error report:

Where you can send error reports

You can specify that SmartHeap send error reports to any combination of the following locations:

Errors detected by SmartHeap

SmartHeap detects the following types of errors:

For an example of error detection and reporting, see the sample program and output SHTESTD.C and SHTESTD.OUT on the following pages.


A sample application that illustrates Debug SmartHeap error reports

The following pages show the SHTESTD.C sample application, which illustrates Debug SmartHeap error reports. Following the listing of the test program is the output it generates. Note that the line numbers in the sample code correspond with those reported by SmartHeap in the error report.

 1 
 2 
 3 
 4 
 5 /* Note: the SmartHeap header file must be included _after_ any 
 6  * files that declare malloc, etc.
 7  */
 8 #include "smrtheap.h"
 9 #include "shmalloc.h"
10 
11 #ifndef MEM_DEBUG
12 #error shtestd.c must be compiled with MEM_DEBUG defined
13 #endif
14 
15 #define TRUE 1
16 #define FALSE 0
17 
18
19 
20 int main()
21 {
22    MEM_POOL pool;
23    unsigned char *buf;
24    int i;
25    unsigned char c;
26 
27    dbgMemSetSafetyLevel(MEM_SAFETY_DEBUG);
28    dbgMemSetDefaultErrorOutput(DBGMEM_OUTPUT_PROMPT 
29       | DBGMEM_OUTPUT_CONSOLE | DBGMEM_OUTPUT_FILE, "shtestd.out");
30 
31    pool = MemPoolInit(0);
32    dbgMemPoolSetCheckFrequency(pool, 1);
33    dbgMemPoolDeferFreeing(pool, TRUE);
34    dbgMemPoolSetCheckpoint(pool, 1);
35 
36    buf = MemallocPtr(pool, 3, 0);  /* this alloc never freed (leakage) */
37 
38    /* invalid buffer */
39    MemPoolInfo(pool, NULL, NULL);
40 
41    /* invalid pointer parameter */
42    MemFreePtr((void *)ULONG_MAX);
43 
44    /* underwrite */
45    c = buf[-1];
46    buf[-1] = 'x';
47    MemValidatePtr(pool, buf);
48    buf[-1] = c;
49 
50    /* overwrite */
51    buf = MemallocPtr(pool, 3, 0);  /* more leakage */
52    c = buf[3];
53    buf[3] = 'z';
54    MemValidatePtr(pool, buf);
55    buf[3] = c;
56 
57    dbgMemPoolSetCheckpoint(pool, 2);
58    
59    /* write into read-only block */
60    buf = MemallocPtr(pool, 10, MEM_ZEROINIT);  /* more leakage */
61    *buf = 'a';
62    MemValidatePtr(pool, buf);
63    dbgMemProtectPtr(buf, DBGMEM_PTR_READONLY);
64    *buf = 'b';
65    MemValidatePtr(pool, buf);
66    *buf = 'a';
67    dbgMemProtectPtr(buf, DBGMEM_PTR_NOFREE | DBGMEM_PTR_NOREALLOC);
68    free(buf);
69    realloc(buf, 44);
70 
71    /* double free */
72    buf = malloc(1);
73    dbgMemPoolDeferFreeing(MemDefaultPool, TRUE);
74    dbgMemPoolSetCheckFrequency(MemDefaultPool, 1);
75    for (i = 0;  i < 3;  i++)
76       MemFreePtr(buf);
77 
78    /* write into free block */
79    c = *buf;
80    *buf = 'a';
81    calloc(1, 3);
82    *buf = c;
83 
84    dbgMemReportLeakage(pool, 1, 2);
85
86    return 1;
87 }

SmartHeap error output from SHTESTD.C

Here's a listing of the SHTESTD.OUT file generated by SHTESTD.C.

MEM_BAD_BUFFER: Invalid buffer parameter.
    Error detected in: MemPoolInfo(01DF:0000, 0000:0000, 0000:0000)
        at line 39 of file shtestd.c, pass #1
    Parameter is NULL pointer.
MEM_BAD_POINTER: Invalid memory pointer parameter.
    Error detected in: MemFreePtr(FFFF:FFFF)
        at line 42 of file shtestd.c, pass #1
    Error at or near address FFFF:FFFF which contains:
        <illegal address>
MEM_UNDERWRITE: Memory before beginning of allocated block overwritten.
    Error detected in: MemValidatePtr(01DF:0000, 01E7:7FF0)
        at line 47 of file shtestd.c, pass #1
    Object created by: MemallocPtr(01DF:0000, 3, 0x0)
        at line 36 of file shtestd.c, pass #1
        checkpoint 1, alloc #1
    Error at or near address 01E7:7FEF which contains:
        78 EB EB EB FC FC FC FC-FC 03 00 14 00 14 00 00   x...............
    Pool last verified in: MemPoolInfo
        at line 39 of file shtestd.c, pass #1
MEM_OVERWRITE: Memory after end of allocated block overwritten.
    Error detected in: MemValidatePtr(01DF:0000, 01E7:7FC8)
        at line 54 of file shtestd.c, pass #1
    Object created by: MemallocPtr(01DF:0000, 3, 0x0)
        at line 51 of file shtestd.c, pass #1
        checkpoint 1, alloc #2
    Error at or near address 01E7:7FCB which contains:
        7A FC FC FC FC 2B 00 00-00 01 00 03 00 00 00 01   z....+..........
    Pool last verified in: MemallocPtr
        at line 51 of file shtestd.c, pass #1
MEM_READONLY_MODIFIED: Memory block marked as read-only was written to.
    Error detected in: MemValidatePtr(01DF:0000, 01E7:7F98)
        at line 65 of file shtestd.c, pass #1
    Object created by: MemallocPtr(01DF:0000, 10, 0x0)
        at line 60 of file shtestd.c, pass #1
        checkpoint 2, alloc #3
    Error at or near address 01E7:7F98 which contains:
        62 00 00 00 00 00 00 00-00 00 FC FC FC FC FC FC   b...............
    Pool last verified in: dbgMemProtectPtr
        at line 63 of file shtestd.c, pass #1
MEM_NOFREE: Attempt to free memory block marked as no-free.
    Error detected in: free(01E7:7F98)
        at line 68 of file shtestd.c, pass #1
    Object created by: MemallocPtr(01DF:0000, 10, 0x0)
        at line 60 of file shtestd.c, pass #1
        checkpoint 2, alloc #3
    Error at or near address 01E7:7F98 which contains:
        61 00 00 00 00 00 00 00-00 00 FC FC FC FC FC FC   a...............
MEM_NOREALLOC: Attempt to realloc memory block marked as no-realloc.
    Error detected in: realloc(01E7:7F98, 44)
        at line 69 of file shtestd.c, pass #1
    Object created by: MemallocPtr(01DF:0000, 10, 0x0)
        at line 60 of file shtestd.c, pass #1
        checkpoint 2, alloc #3
    Error at or near address 01E7:7F98 which contains:
        61 00 00 00 00 00 00 00-00 00 FC FC FC FC FC FC   a...............
MEM_DOUBLE_FREE: Free memory block referenced.
    Error detected in: MemFreePtr(01F7:7FF0)
        at line 76 of file shtestd.c, pass #2
    Object created by: malloc(1)
        at line 72 of file shtestd.c, pass #1
        checkpoint 1, alloc #4
    Error at or near address 01F7:7FF0 which contains:
        DD DD DD DD DD DD DD DD-03 00 14 00 14 00 00 00   ................
MEM_DOUBLE_FREE: Free memory block referenced.
    Error detected in: MemFreePtr(01F7:7FF0)
        at line 76 of file shtestd.c, pass #3
    Object created by: malloc(1)
        at line 72 of file shtestd.c, pass #1
        checkpoint 1, alloc #4
    Error at or near address 01F7:7FF0 which contains:
        DD DD DD DD DD DD DD DD-03 00 14 00 14 00 00 00   ................
MEM_FREE_BLOCK_WRITE: Free memory block was written to.
    Error detected in: calloc(3, 0)
        at line 81 of file shtestd.c, pass #1
    Object created by: malloc(1)
        at line 72 of file shtestd.c, pass #1
        checkpoint 1, alloc #4
    Error at or near address 01F7:7FF0 which contains:
        61 DD DD DD DD DD DD DD-03 00 14 00 14 00 00 00   a...............
    Pool last verified in: MemFreePtr
        at line 76 of file shtestd.c, pass #1
MEM_LEAKAGE: Memory block has not been freed.
    Error detected in: dbgMemReportLeakage(01DF:0000, 1, 2)
        at line 84 of file shtestd.c, pass #1
    Object created by: MemallocPtr(01DF:0000, 10, 0x0)
        at line 60 of file shtestd.c, pass #1
        checkpoint 2, alloc #3
    Error at or near address 01E7:7F98 which contains:
        61 00 00 00 00 00 00 00-00 00 FC FC FC FC FC FC   a...............
MEM_LEAKAGE: Memory block has not been freed.
    Error detected in: dbgMemReportLeakage(01DF:0000, 1, 2)
        at line 84 of file shtestd.c, pass #1
    Object created by: MemallocPtr(01DF:0000, 3, 0x0)
        at line 51 of file shtestd.c, pass #1
        checkpoint 1, alloc #2
    Error at or near address 01E7:7FC8 which contains:
        EB EB EB FC FC FC FC FC-2B 00 00 00 01 00 03 00   ........+.......
MEM_LEAKAGE: Memory block has not been freed.
    Error detected in: dbgMemReportLeakage(01DF:0000, 1, 2)
        at line 84 of file shtestd.c, pass #1
    Object created by: MemallocPtr(01DF:0000, 3, 0x0)
        at line 36 of file shtestd.c, pass #1
        checkpoint 1, alloc #1
    Error at or near address 01E7:7FF0 which contains:
        EB EB EB FC FC FC FC FC-03 00 14 00 14 00 00 00   ................

Return to the Table of contents.


Summary of SmartHeap functions

Task registration

MemRegisterTask
Registers the current task or process with SmartHeap.
MemUnregisterTask
Unregisters the current task or process from SmartHeap.

Memory pools

MemPoolInit
Allocates and initializes a memory pool to store variable-sized and/or fixed-size blocks.
MemPoolInitFS
Allocates and initializes a memory pool, and pre-allocates a specified number of fixed-size blocks.
MemPoolFree
Returns all of the memory in a memory pool to the operating system in one fast operation.
MemPoolSetPageSize
Establishes the size of pages within which SmartHeap sub-allocates.
MemPoolSetBlockSizeFS
Establishes the threshold below which allocation requests are routed to the fixed-size memory manager -- allows small blocks to be allocated very quickly.
MemPoolSetFloor
Establishes the minimum size to which SmartHeap will ever shrink the pool.
MemPoolSetCeiling
Establishes the maximum size of a memory pool -- SmartHeap won't allow the pool to consume more system memory than the ceiling.
MemPoolPreAllocate
Reserves the specified number of bytes for future allocations from the memory pool.
MemPoolShrink
Packs and defragments the handle based memory in the pool, and returns to the operating system any memory that isn't currently in use.
MemPoolCount
Returns the net count of allocations from a memory pool.
MemPoolSize
Returns the total number of bytes of memory allocated within a memory pool.
MemPoolInfo
Obtains information about a memory pool.
MemPoolFirst
Begins enumeration of all SmartHeap memory pools.
MemPoolNext
Continues enumeration of all SmartHeap memory pools.
MemPoolValidate
Checks each entry in a memory pool for consistency.
MemPoolWalk
Traverses a memory pool and returns information about each entry in turn.

ANSI standard C API

malloc
Allocates a block of uninitialized memory.
calloc
Allocates a block of memory and initializes its contents to zero.
realloc
Changes the size of a memory block.
free
Frees a block.

C++ API

new type
Allocates a memory block in C++ from the default memory pool.
new (pool) type
Allocates a memory block in C++ from a specified memory pool.
delete
Frees a memory block allocated with new.

Default memory pool

MemInitDefaultPool
Initializes the memory pool that is used for malloc and new (occurs automatically on the first call to malloc or new).
MemFreeDefaultPool
Frees the malloc/new memory pool.

Fixed-size API

MemAllocFS
Allocates a fixed-size memory block from a memory pool.
MemFreeFS
Frees a memory block allocated by MemAllocFS.

Pointer-based API

MemAllocPtr
Allocates a memory block, returning a pointer.
MemReAllocPtr
Changes the size of a memory block, possibly moving the block.
MemFreePtr
Frees a memory block.
MemSizePtr
Returns the size of a memory block.
MemValidatePtr
Validates a pointer.

Handle-based API (for moveable allocations)

MemAlloc
Allocates a memory block, returning a handle.
MemReAlloc
Changes the size of a memory block allocated with MemAlloc.
MemFree
Frees a memory block allocated by MemAlloc.
MemLock
Increments the lock count of a memory block on the moveable heap, which prevents it from being moved.
MemUnlock
Decrements the lock count for a block, if the block was previously locked with MemLock. The block can move only when the lock count is zero.
MemFix
Increments a block's fix count, which moves the block to the fixed heap. This helps to avoid fragmenting the moveable heap.
MemUnfix
Decrements a block's fix count, which moves the block back to the moveable heap if the fix count is zero.
MEM_REFERENCE
Macro that dereferences the memory identified by a given handle without locking the handle -- implemented as simple double-indirection in non-debug SmartHeap.
MemHandle
Retrieves the handle of the memory block at the specified address (returned by MemLock or MemFix).
MemIsMoveable
Determines whether a block is on the fixed or the moveable heap.
MemLockCount
Retrieves the lock count or fix count of a memory block.
MemSize
Returns the size of a memory block.

Error handling

MemDefaultErrorHandler
The default error-handling function that is in effect if you don't implement your own.
MemSetErrorHandler
Establishes or changes the memory error-handling callback function for the current task.

Miscellaneous

MemVersion
Returns the SmartHeap version number.

Debugging (functions present only in debug version of SmartHeap)

dbgMemSetSafetyLevel
Establishes or changes the level of error checking for the current task or process.
dbgMemSetGuardSize
Establishes the number of guard bytes to pad before and after each allocation to detect overwrites.
dbgMemSetGuardFill
Establishes the character that guard bytes are filled with.
dbgMemSetFreeFill
Establishes the character that free blocks are filled with.
dbgMemSetInUseFill
Establishes the character that allocated blocks are filled with.
dbgMemSetCheckpoint
Establishes the context for allocations -- useful for tracking down overwrites and leakage.
dbgMemPoolSetCheckFrequency
Establishes how frequently the memory pool should be checked for overwrites.
dbgMemPoolDeferFreeing
Causes free blocks to be marked as free rather than actually freed, which helps you detect double freeing or writes into free blocks.
dbgMemPoolFreeDeferred
Frees any blocks that were freed when "deferred freeing" was in effect.
dbgMemProtectPtr
Marks a memory block as readonly, nofree, and/or norealloc. Any attempt to modify, free, or realloc the block (respectively) will be reported as an error.
dbgMemFormatErrorInfo
Formats to a string an error record reported to a SmartHeap error handler.
dbgMemFormatCall
Formats to a string an API reported to a SmartHeap error handler.
dbgMemSetDefaultErrorOutput
Establishes the output destination for the default SmartHeap error reporting mechanism (errors can be directed to any combination of interactive prompt, file, or debugging console).
dbgMemSetEntryHandler
Establishes a hook that is called at each SmartHeap entry point.
dbgMemSetExitHandler
Establishes a hook that is called at each SmartHeap exit point.
dbgMemReportLeakage
Reports blocks that have not been freed between the specified checkpoints.

Return to the Table of contents.


SmartHeap reliability confirmation test suites

A SmartHeap release is sent out only after running the tester for several days -- making millions of calls without a single glitch

Completely error-free operation is, at best, an unrealistic goal for most software products. Yet for a memory manager, rock solid reliability is critical. Tracking down memory bugs in your own application is hard enough -- but bugs in a memory allocator are even more spurious and insidious. These bugs cost companies dearly in terms of programming time, technical support time, damaged reputation, update costs, etc.

Beta tests and an extensive suite of carefully considered test cases are valuable. However, given the number of permutations of inputs and outputs that any program has, especially a memory manager, this approach will cover only a small fraction of the scenarios the program might encounter in actual use.

Because reliability is so important for a memory manager, we developed an automated testing procedure to really prove that SmartHeap works flawlessly. This testing procedure goes far beyond traditional software testing techniques by actually calling each of the SmartHeap APIs hundreds of thousands of times with random parameter values. We won't even add a new function to the SmartHeap Library unless we know in advance that we can verify its reliability through comprehensive testing procedures.

The automated tester is a very sophisticated program. It checks low-memory conditions, passes both valid and invalid parameter values (both randomly generated) to each SmartHeap API, and intentionally double-frees and overwrites previously allocated blocks. The tester allocates blocks from one byte to multi-megabytes, and all sizes in between. In fact, the tester contains substantially more code than SmartHeap itself does.

The test program validates the results and side-effects of every call, and scans each allocated block to be certain that memory is never stepped on when it shouldn't be. It checks that errors (for example, invalid parameters) are reported when they should be and that no errors are reported when they shouldn't be.

Each time the automated tester is run, it generates a detailed log of the results. If any problems are detected, we hold up the release until they're fixed, then run the whole process again. A SmartHeap release is sent out only after we've run the tester for several days -- millions of calls -- without a glitch.

Not even large development teams can afford to do this level of testing to ensure their inhouse memory manager is robust and reliable. That's why so many companies, including Adobe, Autodesk, Borland, Candle, Oracle, Sybase, Informix, Computer Associates, Xerox, Fuji, IBM, HP, Macromedia, WordPerfect, Symantec, and many others, have converted to SmartHeap.


Return to the Table of contents.


Here's what users are saying about SmartHeap

"Programmers who have worked on large projects are far too familiar with the decimation that constant use of malloc() and free() -- or C++ new and delete -- can wreak on available memory and program performance. Into the breach steps MicroQuill's SmartHeap.

This product puts an end to the madness by providing a small library of functions that handle all memory management. Depending on how much you want to rely on SmartHeap (you'll find the more you rely on it the better), you can have it override malloc() and free() or have it work in partnership with these functions.

"Either way, you get a low-overhead package that specializes in fast memory allocation and in avoiding memory fragmentation. It accomplishes both of these tasks exceedingly well and -- most importantly -- reliably. The speed optimization is especially noticeable in systems with paged memory where SmartHeap consolidates frequent accesses into the fewest possible pages. It does all this through a simple-to-use API.

"But there's more. Because SmartHeap manages memory, it can detect memory overwrites, leaks, and other inefficient uses of memory and report them as they occur with detailed error messages -- a wonderful bonus.

"That such a tool is available at all is a blessing; that it is available on MSDOS, extended DOS, Windows, Win32, OS/2, Macintosh, and five flavors of UNIX is a miracle. Save yourself some aggravation and get smart, get SmartHeap."

Andrew Binstock
Software Development magazine
May 1995
(Announcing that SmartHeap won a 1994 Productivity Award for utilities)

"Here's another essential [tool] that is virtually unnoticeable once you've added it, yet it saves you and your customers time. In debugging mode, SmartHeap performs every form of error checking that I know of (and I did write a book on this). The allocation routines in SmartHeap are faster than those in the Visual C++ run-time library. And SmartHeap really shines as your app's memory gets swapped to disk. What I like about SmartHeap is that you can add the code...and then forget that it's there until it points out a bug to you. Or when a user compliments you on how fast your app is."

David Theilen
Microsoft System Journal

"This is my first testimonial in four years; rarely do I run across a programming tool that so completely solves a problem that I cannot imagine how we could have done without it. After looking at these bugs, I am certain that they would have blown up during Beta, would have been impossible to reproduce, and would have caused an extremely painful delay in our product release. My deepest gratitude goes to everyone involved with producing and supporting SmartHeap for playing such a key role in our success. Without SmartHeap, we would have missed this Mother of all drop-deadlines."

Warren Stringer
TestDrive Corporation

"Relinking with SmartHeap v.2.0 improved the overall performance of Lucid 3-D for Windows by 67% -- and many operations are literally 40-50 times faster. SmartHeap is an exceptionally well-designed product."

Robert Duffy
Lucid Corp.

"A malloc/new library that supports all the platforms on which we want to ship, including Windows and UNIX. We tested SmartHeap on advanced RDBMS cases which required over 3 million calls to malloc -- and the last malloc was just as fast as the first. If your code is malloc or new intensive, you can't afford not to use SmartHeap."

Larry Stilwell
Sextant Corp.

"The library you sent me has proven to be rock-solid and blazingly fast. Damn good work!"

Todd Williams
Mobil R&D

"We were faced with a heap-corruption problem that had to be solved that day. Just by linking in SmartHeap we found that the 3rd-party code we were using incremented the pointer to an allocated block and we were calling free with an invalid pointer! We had planned to just use SmartHeap for debugging, but like it so much we ship it with the retail version."

Mark Bowers
Cypress Software Inc.

"SmartHeap v.2.0's capability to detect memory overwrites and leakage have been a big benefit. It plugs in easily and performs like a champ when swapping virtual memory where other suballocators degrade significantly. If you're writing a serious application, you MUST use SmartHeap for memory management."

Mike Griffin
MECA Software, Inc.

"Sometimes a big file in our Windows product 'Timing Designer' would read in 8.5-9 seconds, but after you used the application for awhile it would go up to 50...60...70 seconds. After we linked with SmartHeap, the read time stabilized at 8 seconds, no variation whatsoever. Then, by tuning the app with a couple of fixed-size heaps, I was able to shave off another 1.3 seconds. I think it's great!"

Mike Meredith
Chronology Corp.

"By merely relinking with SmartHeap and changing our .mak file in our OS/2 2.x application, we got an instant 50% overall performance improvement."

Dave Middleton
Trilogy

"Sure, you could probably roll your own memory manager for Windows. But, SmartHeap offers a *fast*, robust, and most importantly, *fully debugged* memory manager for a fraction of the time, effort, and money."

Steven Antoch
Arcland

"We've been shipping with SmartHeap for over 18 months -- and we have not found or even heard about a single bug. That's reliability!"

Rick Williamson
FarPointe Technologies

"Even when not in low-memory conditions, we found that, for test cases that involved large numbers of small objects, the performance of the application with SmartHeap v.2.0 was MUCH better. We are pleased with the choice of SmartHeap and have adopted it as our default heap manager."

Ken Burgett
Xerox Group Communications

"TrackRecord used to thrash due to the design of the compiler-supplied allocator. We plugged in SmartHeap and the problem was solved! TrackRecord now shines in all memory situations. I highly recommend it!"

David Nanian
Underware, Inc.

"SmartHeap saved our butt in AutoCAD development. In addition to providing an immediate performance boost, it gave us increased stability on Win32s and -- most importantly of all -- incredible Error Checking."

Robert Wenig
AutoCAD Development
Autodesk

"Why write your own memory manager? SmartHeap is fast, compact, cross-platform, and very reliable. And the extensive debugging features helped us a lot in the development stage."

Ning-Ju Nan
Adobe

"I use SmartHeap under MSVC with our BIG Windows app. It works quite well, and the code is quite good. (I found 1 bug that was triggered by a large set of really obscure conditions. It was fixed promptly. That is the only problem in 3 years of usage.) That is one of the two DLLs that I have purchased that WORK reliably -- the other 6 or so have been buggy as sin."

John Lussmyer

"Just by linking with SmartHeap's runtime libraries, our performance improved 1.6 to 5 times (depending on platform) versus the default memory manager. Nothing has been so easy before, especially on OS/2. It also has a great API for debugging heap bugs -- we saved a lot of time finding memory leaks by using SmartHeap. The documentation is excellent, too."

Kurt Shurenberg
Actamed

"SmartHeap has saved my tail many, many times without a single false alarm. I haven't been using it real long, but so far every time it has yelled, there's been a real bug."

Geoff Chalmers
Atlanta Development Center

"SmartHeap integrates easily with C++ to provide a much-improved new and delete."

David Mandell
Plannet Crafters

"Using SmartHeap on NT helped us to deliver a cleaner, faster voice recognition system on time. It's great to find a product that does everything it says. Every programmer should use it."

Roy Russell
Kurzweil

"We have been using SmartHeap for Windows for one week and this is a really wonderful product. In some circumstances, the average performance of GeoConcept improved by 100%. Using SmartHeap's memory pools, fixed-size allocators, and handles allowed us to implement new functions we could not have included otherwise. Thanks to SmartHeap, it has really been a breeze to add and debug these new functions."

Luc Coiffier
Windows Product Manager
Alsoft

"SmartHeap is the only third-party library we use in our development. While many other libraries seem to be solutions in search of a problem, SmartHeap gives us something we genuinely need: performance- and space-efficient, flexible Windows memory management with exceptional diagnostic support. Thanks for an excellent product."

David Rosenbaum
Blue Ribbon Soundworks


Return to the Table of contents.


Partial list of SmartHeap customers

Abacus Research AG ** ABC Technologies ** ACE Software ** Acer ** Adaptive Software ** Adobe ** Adonis ** AG-Tech ** AGA Computer Services ** Agency Management Services ** Allegro ** Alliance InfoNet ** Allied Signal Technical Services ** ALUR ** Amak Communications ** American Airlines Decision Technologies ** American Computer & Electronics ** American Power Conversion ** Anagraph ** Answer Software ** Apex Group ** Apple Computer ** Applied Automation ** APPS ** Apsylog ** APT Arbor Software Arcland ** Arctco ** ARGO Data Resource ** Arinc Research ** Array Analysis Arthur Andersen ** Artifex Tech ** Asais ** Aspect Telecommunications Astra Pharma ** Asymetrix ** AT&T Bell Labs ** Attain ** Automated Data Systems ** Automation Technologies ** Avail Systems ** Avanti Software Avantos Performance ** Aviato A/S ** Avid Technology ** Aware Technology Axon Instruments ** Azeroth ** Bachman ** Bacmac Ltd ** Banker's Trust Barra ** Battelle NW ** Baxter Diagnostics ** Beckman Instruments ** Bell Northern Research ** Bellcore ** Besserman ** Best Programs ** Betz Laboratories ** BioRad Labs ** Borland ** Boston Treasury Systems ** Breakthrough Brookline Systems ** Bull HN ** Burl Software Businessware ** C-Tree Systems ** Calera Recognition Systems ** Cambridge Technology ** Canary Labs ** Canon Information Systems ** Capital Management Sciences ** Carson/Banks & Associates ** CDA Investment Technologies ** CE Software ** Centerview Software ** Central Intelligence Agency ** Century CHC ** Chronology ** Cimflex Teknowledge ** Cincinnati Bell Info Systems CJ Enterprises ** Clarify ** Claritas / NPDC ** CLS Research P/L ** CMS Data ** CODA Music Software ** Cognos ** Columbia Software ** Compaq Computer Compatibility Development Co ** Compton's New Media ** Computer Associates Computer Intelligence ** Computer Voice Systems ** ComputerVision CompuTrac ** Connally Consulting ** Continuum ** Cooperative Solutions Cornerstone Information Systems ** Cortex ** Craftech Software Designs CSTI ** CTA ** Curo ** Customer Insight Co ** Cybermedix ** Cyme International Cypress Software ** Dana Communications ** Data Broadcasting ** Data I/O ** DEES Communications ** Deloitte & Touche ** Delrina ** Dendrite International ** Design Maintenance System ** Diagnostics and Measuring Systems ** Diamond Head Software ** Digibotics ** Disk Software ** DMIS Dow Jones Telerate ** DSSC ** Dynamics Research ** Dynix Marquis ** E-Scan Earth & Ocean Research Ltd. ** Ed Friends ** Edge Information System ** EDS ** Eicon ** Eidoloan ** Electronic Book Technology ** Electronics for Imaging ** ElectroPeru S.A. ** Ellsworth Associates ** EMC Software Development ** Enable Software ** Enatec Software ** Engineered Business Systems ** Entek ** Enter Software Intl ** Entropy ** Epic ** ERG Electronics Ergo Sum ** Erisco ** Essential Technology ** Expert Edge ** Fannie Mae FarPoint Technologies ** Fastlane Tech ** Fasttrack ** FG&A Software Fidelity Investments ** Firma Leibetseder ** First Data ** Folio ** Foresight Forum SQL AB ** Frank Russell Company ** Frontline Systems ** Frye Computer Systems ** Fujitsu Europe Telecom ** Fujitsu Network Transmission Fusion Software ** GE Information Services ** General Analytics ** General Technology ** Geodesic Systems ** Geographic Data Technology Geographix ** Georgetown Systems ** Georgia Tech ** Geovision Systems Gespower SA ** Giro ** Global Advanced Tech ** GPA Capital ** Graphic Development ** Great Plains Software ** Gregg Engineering ** Halcyon Software ** Harvard Toolworks ** Haven Tree Software ** Hewlett-Packard High Plains Software ** HMS Software ** Host Engineering ** Howling Dog Systems ** Hyprotech ** I-Kinetics ** IBAX Healthcare ** IBM ** ICOM Ideal Learning ** Image Business Systems ** Image Data ** Image Science ImageTech ** Imaging Research ** IMSI ** Indigo ** Individual Software Infocast ** Information America ** Information Resources ** Information Systems Assoc. ** Information Systems Manager ** Informix Software Infors Control AG ** Infotech ** Innovative Software GmbH ** Insight Insoft ** Instron ** Instruments S.A. ** Intec ** Integrated Systems Applications ** Integrated Technology ** Intek ** Intel ** InterAccess Interface Logic Systems ** Intergraph ** Interleaf ** Intersolv ** Intuit INVZN Development ** IRC ** IRD Mechanalysis ** Irisoft ** Ivid Communications Ixian SA ** Jandel Scientific ** JetForm ** Job Boss Software ** Johns Hopkins University ** Johnson Controls ** Jostens Learning Center JTS Computer Systems Ltd. ** Kansas City Life Insurance Co. ** Keithley Metrabite ** Kenonic Controls ** Kinetec ** KJ Law ** Knowledgeware ** Knowlogic Kodak ** Kortex International ** Kurzweil Applied Intelligence ** Kwasha Lipton ** Lan Design ** Laser Key ** Laurentian University ** LCC ** Lead Technologies ** Learned-Mahn ** Legent ** Lenel Systems International Level Five Research ** Levi Ray and Shoup ** Life Touch Learning Light Source ** Logisoft ** Logitech ** Logos Research Systems ** Look Systems ** Los Alamos National Lab ** Lotus Development ** Lucid ** Lynx Software ** MacTool Kit ** Macro Ed ** Magna Software ** Mainstream Data Mammoth Micro Productions ** Map 80 Systems Ltd. ** MARC ** Marketing Resources Plus ** Matesys ** Mattson Instruments ** Maximal Systems MAXM Systems ** Maybon Securities ** MCI Telecommunications ** Mecca Software ** Mediashare ** Medstat Systems ** Mentor Communications Ltd. Merak Projects ** Merrill ** Mesonic USA ** Metz Software ** Micro Computer Power ** Micro Insurance Software ** Micro Technology ** Micro-Frame Technology ** micro80 A/S ** MicroBank ** Microbrightfield ** Microcrafts MicroGrafx ** Micrographic Teknowledge ** MicroHelp ** Microrim ** MicroScan Microsoft ** Microsystem Options ** Microtec Research ** Mikrotaurus Millipore ** Milsoft Integrated Solutions ** MindStorm ** Minicom Data Mission Critical Software ** Mobil ** Mobius ** Modern Software ** Motorola Mountain Network Solution ** MPR Teltech ** MultiData ** MultiQuest Munro Garrett ** Musical Dynamics ** National Demographics ** NationsBanc NCR ** NCS Access Control ** NEBS ** NEC America ** Netronic Software Netwise ** Network Computing ** Network General ** Neurometrics Institute Nevendorf Systems ** Newmarket Software Systems ** Nicolet Instrument Nielson Marketing Research ** Nintendo of America ** Novadigm ** Novalog Novell ** Objective Solutions ** Octocom Systems ** Office of the Future Omega Group ** On-top Systems ** One Tree Software ** OneSource Information Services ** Online Computer Library Center ** OPENetwork ** Operation Technology ** Optima Technologies ** Optimas ** Opto 22 ** Oracle ** Orange Co. Property Appraisers ** Oregon Judicial Dept-Info Systems Dept Oregon State University ** Orion Scientific Systems ** Ortho Diagnostic Systems ** Overdrive Systems ** Pacific Current Info Systems ** Pacific Sierra Research ** Panttaja Consulting ** Parallax Software Technologies Pathfinder ** PE Nelson ** Peak Audio ** Peakdesign ** Peer Systems ** Perkin-Elmer ** Personal Library Software ** Personal Travel Technologies Peter Norberg Consulting ** Philips ** Phototelesis ** Pilot Software Pinpoint Publishing ** Pitney Bowes ** PK-Ware ** PKC ** Plannet Crafters Plus III Software ** Portfolio Software ** Portfolio Technologies Premier Solutions Ltd. ** Price Waterhouse ** Primavera Systems ** Prodigy Services Company ** Production Data Services ** Promark Software Prometrix ** ProtoLink ** Public Systems Associates ** Pygmy Computer Systems ** Quad Graphics ** Quant Trading ** Quotron Systems ** Race Industries Radio Computing Services ** Raynet ** RBC Dominion Securities ** RDA Consultants ** RDS ** Reality Technologies ** Remedy ** Remuera Educational Service ** Report Smith ** Reuters ** Rise Time ** Rogers Cablesystems Roy-G-Biv ** S-Cubed ** Sable Technologies ** SAIC ** SCC ** Scott & Scott ** Scott Instruments ** Service Systems International ** Sextant ShareVision ** Sheshunoff Information Service ** Shure Brothers ** Sierra On-Line ** Silicon Dragon ** Simtech ** Simware ** SKM Systems Analysis ** Smart ** Smith Kline Beecham ** SoftTest ** Software Artistry Software Metrics ** Software Pursuits ** Software Toolworks ** Solutions By Design ** Southern California Edison ** Southwestern Bell Telephone Southwire ** Speedware ** Spinnaker Software ** Sterimatics ** Stonesgate Strata ** Strategic Controls ** Sungard ** Sun Hydraulics ** Sybase ** Symantec ** Symbus ** Synopsys ** Syntell ** Tally Systems ** Tandem ** TASC Taylor Industrial Software ** Taylorix AG ** TCI Software Research Inc. ** Tec Pull Software ** TechniSoft ** Technomation ** Tecmar ** Tellabs Operations ** TestDrive ** Texas Instruments ** Blue Ribbon SoundWorks The Computer Center ** The Dodge Group ** The George Group ** The Ridge Tahoe ** The Whitewater Group ** Thermo Jarrell Ashe ** Timothy Martin Tomlinson Consulting ** Total Control Products ** Townsend Analytics Ltd. ** Trace ** Trane Co ** Traveling Software ** Trax Softworks ** Trilogy Trimetrix ** TRW-REDI ** TSI ** UIMS ** Underware ** Unimax ** Unisys ** US Computer ** US West MRG ** VA Medical Center ** Ventritex ** Ventura Micro Verbex Voice System ** Viewstar ** Virgil ** Virtec Systems ** Virtus WK Information Systems ** Walker Richer & Quinn ** Wall Data Walt Disney Imagineering ** Wang Laboratories ** Ward Software ** Ward Technology ** Watchtower ** Waverly Systems ** Wellesley Communications West Publishing ** Westinghouse Electric ** Whitetree Network Technologies Wiechers & Partner Datentechnik GmbH ** Wilcox Associates ** Wordperfect ** Workgroup Systems ** World Motor Trading ** Wyatt Software Xerox ** Xsoft ** Z-World ** Zenographics


Return to the Table of contents.