HeapAgent/SmartHeap cause first chance exceptions in the debugger

  When you run your application under both HeapAgent or SmartHeap and your source debugger at the same time, your debugger may report one or more first-chance exceptions in the HeapAgent DLL. These exceptions are caused by HeapAgent's address validation, which uses Win32 structured-exception handling. The exceptions are handled by HeapAgent and are not errors in your application or in HeapAgent.

The following is taken straight out of the HeapAgent manual:
"HeapAgent causes a number of first-chance exceptions during its normal operation. These are the result of address validation that HeapAgent performs while validation parameters and querying the preexisting heap implementation during heap patching. These first-chance exceptions are not errors in your application or in HeapAgent. You can safely ignore them. You should therefore configure your debugger to continue on first-chance exceptions."

There is no way to avoid the FCE's caused by HeapAgent/SmartHeap, short of disabling SmartHeap patching. They are much less prevalent in runtime SmartHeap. We understand the problem this creates if you are trying to debug your own exceptions. Note that NT itself uses excpetion handling and generates FCE's all the time, but the VC++ debugger doesn't stop on these since it knows that they are OS FCE's and hence that they are OK. Alas, VC doesn't treat SmartHeap FCEs the same as it treats the OS FCEs.


Suppressing Message Boxes

HeapAgent (or debug SmartHeap) users will sometimes see the "HeapAgent is unable to find memory allocation..."etc) message box. Beginning with SmartHeap 5, you can avoid this message: add the registry value DWORD "SkipDLLMessagesOn" to either "HKEY_LOCAL_MACHINE\Software\MicroQuill\HeapAgent\" (to affect all apps) or "HKEY_LOCAL_MACHINE\Software\MicroQuill\HeapAgent\Apps\ <full path of app (e.g., c:/foo/bar.exe)>" (to affect just one app), and set this value to zero. By default, HeapAgent will continue to prompt, but it will just ignore DLLs without heap symbols if the above registry value exists and is set to zero.

For earlier versions of SmartHeap and HeapAgent there is no way to automatically suppress this message box. HeapAgent allows you to suppress subsequent messages, and to disable patching on the specific DLLs, or on all DLLs, which will also keep the message from appearing. Both these fixes require either that the message appear at least once (so that you can choose to suppress it), or that you know in advance which DLLs you want HeapAgent to skip.


Calling MemRegisterTask

Some tips on using MemRegisterTask:

  1. With the latest versions of SmartHeap for win32 (3.31 through 6.x) , it should not be necessary to call MemRegisterTask at all.
  2. If your Unix app runs on a single thread, you don't need to call MemRegisterTask.
  3. When you link your multi-threaded UNIX app to SmartHeap, you do need to call MemRegisterTask from the first thread before secondary threads call SmartHeap. This ensures that SmartHeap can initialize synchronization objects before they're used.
  4. You need to call MemRegisterTask only once, before the second thread starts, regardless of how many threads your app uses.
  5. If your multi-threaded UNIX app uses a third-party product which creates threads on its own at startup you should consider whether those threads will be created before you call MemRegisterTask from main. If so, and if those threads call malloc (which is likely), this could cause problems. One workaround would be to create your own shared lib that calls MemRegisterTask during startup, and link this DLL after the thread lib but before the third-party lib?
  6. Please see the SmartHeap Getting Started guide for your platform for more information on using MemRegisterTask.

Stack checking

Note: HeapAgent 6 and some late (2000/2001) releases of HeapAgent 3.12 do not support stack checking. If your version of HeapAgent was released prior to the year 2000, read on for info on the limitations of this feature.

If you enable stack checking (compile with /Ge and turn on stack checking in the HeapAgent Settings dialog) HeapAgent will check for overflows of the stack frame. It will not check for overflows of individual local variables within the frame. So the error in this code:

Char str[5];
Strcpy(str, "abcdefg");

won't be detected by HeapAgent unless the overwrite is large enough to extend outside the stack frame. In this example, the compiler will allocate 8 bytes for local variable str for alignment reasons. There is no way to tell from an analysis of the stack that the source code shows an allocation of 5 bytes when 8 bytes were actually allocated. This is unlike malloc(5), where HeapAgent is performing the allocation at runtime so HeapAgent can see the size 5 being passed in even if the compiler CRT would have allocated 8 bytes. In the case of the stack, the number 5 exists only in source code, not in object code or at runtime).


File and line info using Borland compilers

If you follow the instructions in the Getting Started guide for using Borland compilers you should get full file/line info in your error reports. However, there is a limitation in HeapAgent 3.12 and HeapAgent 6 when used with the Borland compiler. In Win32 HeapAgent/debug SmartHeap obtains file/line info from compiler debugging info -- but only VC++ debug info is supported, not Borland. In HeapAgent 3.11 (SmartHeap 3.31) and earlier, Borland users could capture file/line info for calls to operator delete, but this capability was removed in HeapAgent 3.12 because its implementation required thread-local storage, which has an OS bug that potentially corrupts static data in the app in NT 4 when used from a dynamically-loaded DLL (such as the HeapAgent DLL when auto-loaded). Thus, HeapAgent 3.12/6 cannot give you file/line info for operator delete on apps compiled with Borland C++. Registered users of HeapAgent 3.12/6 can contact MicroQuill tech support and request a free copy of HeapAgent 3.11, which will give info for operator delete.

Using SmartHeap with the STL

If the default STL allocator, Allocator::Allocate, is implemented in terms of operator new, it would automatically allocate via SmartHeap if SmartHeap is defining new.

If you want an STL allocator that uses SmartHeap multiple pools, this would be trivial to implement directly with public SmartHeap APIs: just pass a SmartHeap pool as the "hint" parameter to Allocator::Allocate and have it call MemAllocPtr().


File and line info using VC++

Four possibilities:

  1. Missing compiler files. HeapAgent/debug SmartHeap relies on two files for debugging info: [appname].pdb and mspdb??.dll. Typically [appname].pdb is in the same directory as the EXE/DLL being debugged and mspdb??.dll is in the compiler's bin directory. If the EXE or DLL was compiled on another machine, try copying these two files into the test machine.
  2. The allocation is being created in a DLL for which you don't have source. If you can find a .PDB file laying around for those DLLs (some .PDB files are included with VC DLLs, for example) copying them around appropriately might get you some function names.
  3. VC 6 Users: The problem may be that HeapAgent/debug SmartHeap can't find the file mspdb60.dll. Try copying this file to a folder in your system path.
  4. (specific to SmartHeap version 5 and 6 and HeapAgent releases after Jan 2000) There are two situations where recent versions of HeapAgent/debug SmartHeap will not provide file/line information:
    1. calls to system heap functions (GlobalAlloc, HeapAlloc, etc)
    2. heap calls in a DLL that's loaded with LoadLibrary

      If either of the above applies to your app, try enabling system heap patching. To do this, select your app in HeapAgent App Setup, click the edit button and check the box Patch GlobalAlloc/LocalAlloc/HeapAlloc. Enabling system heap patching will also cause HeapAgent to patch LoadLibrary. If you try this and it causes other problems, uncheck the box Patch GlobalAlloc/LocalAlloc/HeapAlloc and (if applicable) enable LoadLibrary patching via the registry as explained here.

    If you're not using HeapAgent, you can enable system heap patching via the registry. See your Getting Started Guide for details.


Using HeapAgent with an NT Service app (HeapAgent)

The only limitation that we're aware of with respect to using HeapAgent with NT services is if the service is started by the system before logon (and hence before the window system is up), the HeapAgent UI and error report dialog boxes are not available. In this case, you should uncheck the AutoLaunch HeapAgent User Interface box in HeapAgent App Setup and configure HeapAgent to log errors to a file.

Following are some suggestions for debugging DLLs loaded by inetinfo.exe:


Preventing autoloading (HeapAgent)

To prevent autoloading:

  1. Go into HeapAgent Application Setup and add your app to the list (if you haven't already done so). Click on the Edit button and uncheck "Autolaunch HeapAgent user interface". Click OK & close App Setup.
  2. Start HeapAgent and open your application (use Open in the File menu or use the recent files list). Go to the Options menu and uncheck "Stop on errors".
  3. In the File menu, click on "Save environment now". Then close HeapAgent.
Now when you run your app the HeapAgent interface will not launch and no HA error windows will appear. If you want the error reporting but not the windows, click on "Log to file" in the options menu and HeapAgent will write the error report to a log file.

Problem with log files (HeapAgent)

For a short time there was a bug in HeapAgent 3.12 which prevented writing errors to the log file. The log file was created but empty. If you experience this problem please contact MicroQuill tech support for the fix.

Detecting overwrites

Typically HeapAgent will report the function call that created the allocation, but not the specific line of code that made the overwrite. HeapAgent instruments only heap functions (malloc, new, etc) but the code that creates the overwrite (a strcpy for example) typically is not a heap function. HeapAgent automatically checks for overwrites on termination, but you can configure an Agents that checks for overwrites at specific points in your code. You can also use the Find Overwrites... option in the debug menu. In this way you can zero in on the code that's causing the problem. For more info, see Chapter 9 of the HeapAgent User's Guide.

Sharing debug settings (HeapAgent)

HeapAgent stores most of its app-specific configurations in an [appname].hpa file which it creates on-the-fly and stores in the folder of the EXE being debugged. This file contains debug settings accessible through the HeapAgent UI (guard size, deferred freeing queue length, etc) as well as the list of "suppressed" errors. The .hpa file can be copied and distributed to other users. By placing the file in the folder of the EXE being debugged, users can standardize debug settings. The patching settings configured using HeapAgent App Setup are stored in the registry and can't be shared as easily, though there is a save/restore branch feature in RegEdit that might be useful. The reason these settings aren't in the .hpa is that they are needed by SmartHeap and SmartHeap doesn't have a UI to generate an the *.hpa file.

Problems installing/uninstalling HeapAgent

Installing:

'Out of Memory' error when trying to install HeapAgent -- This problem can occur when your operating system is booting with the /3GB flag. Fix is to remove the flag from boot.ini, reboot, install HeapAgent, then restore the flag.

Uninstalling:

Always uninstall before installing a newer version, as previous versions of HeapAgent may cause problems for a new installation. If this problem is suspected, the fix is to uninstall HeapAgent, verify that HeapAgent references in the registry and HeapAgent files in the system folders have been removed, and then reinstall. The following procedure should accomplish this. This procedure can also be used to remove HeapAgent from your computer if the uninstall program misfires. NOTE: HeapAgent and SmartHeap share libraries and DLLs. If you are a software developer and have SmartHeap installed on your machine, debug SmartHeap may create registry entries referencing the HeapAgent DLL and/or HeapAgent libraries. Exercise care when editing the registry, and call MicroQuill tech support if you have any questions. You should not manually delete the HeapAgent DLL if you have SmartHeap installed.

  1. Run the HeapAgent uninstall from Control Panel or the HeapAgent uninstall utility (in the HeapAgent program group). If there are problems running uninstall, you can manually delete the files in your HeapAgent folder and sub-folders. Check and delete haloader.dll and shw32d.dll (HeapAgent trial version users delete ha312w32.dll) from the system folder.
  2. Check the following registry areas to ensure haloader.dll and haloader.exe are removed. HKEY_LOCAL_MACHINE\Software\Microsoft\WindowsNT\CurrentVersion\Windows\AppInit DLL (haloader.dll entry) HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run (haloader.exe entry)

    Obligatory warning: Yikes! Please take care when editing the registry!

  3. Restart your computer. If you had problems running the uninstall program, search for the file haloader.exe and delete it if found. Reinstall HeapAgent if appropriate.

Compile errors on 32-bit HP-UX 11

Note: This problem most likely will not occur in SmartHeap 6.02 and later.

Including smrtheap.hpp in an app on this platform may draw a compile error similar to the following:

Error 606: "smrtheap.hpp", line 138 #Missing exception specification; "void (*set_new_handler(void (*)()))()" was previously declared with an exception specification at ["/opt/aCC/include/new.h", line 52] _CRTIMP pnh MEM_ENTRY_ANSI set_new_handler(pnh) MEM_CPP_THROW;

The workaround is to remove the "&& defined(__LP64__)" from line 76 of smrtheap.hpp. smrtheap.hpp should be correct as is for either pre 11.0 HP-UX or 64-bit 11.0).

Compile and link errors referencing set_new_handler in smrtheap.hpp

On all platforms, if you get a compile error referencing the set_new_handler declaration in smrtheap.hpp, comment out that declaration. Usually that is all that's required to fix this problem.

If after commenting out the declaration in smrtheap.hpp you get a link error like the following, more drastic action may berequired.

/usr/ccs/bin/ld: Unsatisfied symbols:
exception::~exception() (first referenced in
SmartHeap/v6/hpux-11.00_acc33/lib/libsmartheapC_mtd.a(s
hnew.o)) (code)
typeid<exception> (first referenced in
SmartHeap/v6/hpux-11.00_acc33/lib/libsmartheapC_mtd.a(shnew.o
)) (data)
Class tables [Vftptr] dependent on key function:
" exception::~exception()" (first referenced in Smar tHeap/v6/hpux-11.00_acc33/lib/libsmartheapC_mtd.a(shnew.o)) (data)

What you may need to do is compile the SmartHeap source files shnew.cpp and (in version 6.03 and later) shnewi.cpp, and link to shnew.o and shnewi.o instead of libsmartheapC*.a. Contact MicroQuill tech support for platform-specific instructions.

The difference between mmap and sbrk

Note: Only SmartHeap ver. 3.x for UNIX offers separate mmap and sbrk libs.

The sbrk() approach grows the heap and the process address space in page increments as the sum of allocations and unallocated, fragmented heap space increases. Most tasks eventually reach some typical maximum heap footprint which remains constant with time. This technique is most efficient and is the default. The mmap() approach grows the heap and the process address space as required to contain all of the current allocations. Large unallocated blocks of the heap are returned to the OS for use elsewhere in the system.Ê Of course, some of the heap will remain unallocated and fragmented. This technique is less efficient, but is well suited to a few situations in which the sbrk() technique runs out of heap space prematurely. Our recommendation is to adopt the sbrk() approach for maximum flexibility and performance. If a problem is observed in your environment with excessive process address space, then you should consider trying the mmap() build to see if it helps. By default we ship the sbrk() version of SmartHeap. If you want to try the mmap() version, please contact us. The following text appears in the readme file included with most Unix versions of SmartHeap: ãThe version of SmartHeap on this install disk uses sbrk to allocate memory from the operating system.Ê In rare circumstances, you may discover that this uses excessive amounts of memory.Ê If you encounter this problem, please contact us and we'll send you a version of SmartHeap that uses mmap to allocate memory from the OS.Ê However, be aware that mmap is significantly slower than sbrk.”


HeapAgent and Emacs for Windows

In every process HeapAgent loads a tiny stub DLL that determines whether the actual HeapAgent DLL should be loaded in the current process. This enables HeapAgent to auto-load in applications by simply adding the app name to HeapAgent's setup utility. Unfortunately, the address used prevents Emacs from initializing.

There are several workarounds:

  1. Change the default load address of haloader.dll to an address that Emacs doesn't use. The following command will do this:
    editbin /rebase:base=0x20000000 haloader.dll.
  2. At least one recent version of Emacs (Emacs 20.3.5.1, available at http://www.cs.washington.edu/homes/voelker/software.html) appears to have fixed the Emacs/HeapAgent conflict.

Run under debugger

The most convenient usage model for using MSDEV or MSVC with HeapAgent is to simply run the app under the debugger. HeapAgent will then load automatically with the app (provided the app is either specified in HeapAgent App Setup or linked with the HeapAgent lib) and you can debug normally under MSDEV/MSVC. Since the normal usage pattern under MSDEV/MSVC is to debug in the same session that is used to edit and compile, the spawn debugger option in the HeapAgent UI should rarely, if ever, be used. In other words, run the app under MSDEV/MSVC rather than running under the HeapAgent UI, because an existing instance of HeapAgent can connect to a running instance of an app whereas an existing instance of MSDEV/MSVC cannot.

The factory-default debugger command-line in HeapAgent 3.1? is "msdev -p%ld -e%ld". The command-line for VC++ 4.x/5.x is "msvc -p%ld -e%ld". If the command-line is changed for a particular app, that will continue to be the default for that particular app.


"HeapAgent is unable to find memory allocation symbols in [filename]"

The named EXE or DLL isn't linked with Microsoft Visual C++ PDB debugging information, and it is statically linked instead of dynamically linked with the C Runtime Library. You must either link with debugging information or link with the C Runtime DLL. To specify PDB debugging information:

  1. Choose Settings from the Project menu, choose the C/C++ tab, change Category to "General" and change the value of Debug Info to "Program Database".
  2. Select the Link tab, change Category to "General", and check "Generate Debug Info".

To specify the C Runtime DLL in Microsoft C++:

  1. Choose Settings from the Project menu, choose the C/C++ tab, change Category to "Code Generation", and change the value of Use Run-Time Library to "Multithreaded using DLL".

To use the Microsoft Foundation Class as a DLL:

  1. Choose Settings from the Project menu, choose the General tab, and change the value of Microsoft Foundation Classes to "Use MFC in a Shared DLL (mfcX0(d).dll)", where X is 3 or 4, corresponding to the version of Visual C++ you're using.

Adding DLLs in HeapAgent App Setup

The sole purpose of the "Name of DLL to Add" edit control is to add a DLL to the list box "Patch heap routines in these DLL's:" and then use the right arrow and move the added DLL over to "Do NOT patch heap routines in these DLL's:". HeapAgent automatically patches all DLLs that are not specified in the "Skip DLLs" list. There is no internal list of DLLs to patch -- the "Patch these DLLs" list is simply those DLLs referenced by the EXE that aren't skipped. If a DLL is dynamically loaded and you want it patched, no action is required as this is the default. If you want a dynamically-loaded DLL to be skipped, then add its name and move it to the "skip list".

SmartHeap vs. HeapAgent

SmartHeap is two libraries in one. There is the debug library designed to catch bugs in your code and a runtime library optimized for speed. The obvious difference between SmartHeap and HeapAgent is that the latter does not include a fast runtime library. SmartHeap and HeapAgent share the same debug library. Both offer a debug API that can be used to customize over two dozen different debug settings, format and redirect error reports, etc. HeapAgent accesses this API through a Graphic User Interface -- a feature not available in SmartHeap. For example, to change the number of guard bytes around an allocated block a SmartHeap user can insert in his code a call to the API dbgMemSetGuardSize. A HeapAgent user can accomplish the same end by simply opening the Debug menu and changing the Guard Size setting. No coding is required (HeapAgent users can also use the API directly if desired). The HeapAgent interface also includes a nifty collection of tools to aid in debugging: The allocation browser contains information (callstack, block size, et al) on all allocations monitored by HeapAgent. The source browser enables you to click a button and view the line of code that is linked to an error detected by HeapAgent. The dump browser is a raw memory dump which can be viewed in a variety of formats. The Agent utility can be programmed to automatically change debugging settings, set breakpoints or check for errors at strategic points in your application.


Saving browser info (HeapAgent 3.12 and earlier)

There is no way to dump the browser info to a file using the HeapAgent 3.12 user interface. Nor can you cut and paste the data in the browser. You can overcome this limitation programmatically: just call the HeapAgent API dbgMemWalkHeap and fprintf whatever details are desired to a file. If file/line or other debug info is desired, use dbgMemPtrInfo to get that information for each in-use allocation. For details, see the FAQ entry on obtaining callstack info.

HeapAgent 6 and later does not have this limitation.


Obtaining callstack info (HeapAgent 3.12 and earlier)

The HeapAgent user interface is not ideally suited to displaying long callstack chains. You can increase the max number of chains to 16 in the Debug menu (under Settings). In an error report window or textual error log file you can scroll the length of the chain, but in the HeapAgent browser window your screen size/screen resolution is an absolute limit on how much you can see. Unfortunately there is no easy way to dump/paste browser data to a file or a spreadsheet. You can obtain callstack info programmatically with the API dbgMemPtrInfo or by using dbgMemSetEntryHandler/dbgMemSetExitHandler. These will fill the callstack field of DBGMEM_PTR_INFO and MEM_ERROR_INFO, respectively, with addresses of functions on the stack at the time the alloc was created and the time of the heap call, respectively. This isn't quite clear from the description of these API's in the Programmer's Guide, but see the definition of DBGMEM_PTR_INFO and MEM_ERROR_INFO in heapagnt.h.

HeapAgent 6 and later does not have this limitation.


Browsers not available at termination (HeapAgent)

There are cases where the HeapAgent UI can't be used at termination. Specifically, it is when the HeapAgent UI hasn't connected with the debuggee process prior to termination, or when the user32.dll in the debuggee process has terminated at the time of the leakage report. This is more likely to occur in a console app that auto-loads the HeapAgent DLL, or one that terminates very soon after initializing. The HeapAgent eror report dialog will have the source file/line though, so just use an editor to browse the source.

Finding heap size

The SmartHeap API MemPoolSize(pool) will return the total number of bytes of OS memory consumed by a memory pool. To get the number of bytes of in-use memory in a pool you can use MemPoolWalk(..) to traverse pool entries & collect the info. Please note that, as our Programmer's Guide says, MemPoolWalk "is intended for debugging, and should not be used for performance-critical tasks". If your app is multi-threaded or if you are explicitly creating multiple SmartHeap pools, you'll need to collect statistics on each pool for a complete report on memory use in the process. The APIs MemPoolFirst/MemPoolNext provide a relatively painless way to visit each pool.

Debug symbols for release builds

You may be able to coax some marginally useful feedback out of HeapAgent with this setup, but we don't recommend it and we don't support it.

Attach to a running program (HeapAgent)

A running application should show in the 'Attach running program' box if one of the following is true:

  1. You have already debugged this app with HeapAgent in the current HeapAgent session, before detaching from it in order to attach to another program.
  2. The app is linked with the HeapAgent lib file and set up in HeapAgent Application Setup. Normally a program that meets these two criteria would cause HeapAgent to launch automatically when you ran it, but this automatic launching can be disabled in HeapAgent Application Setup

Breaking in the debugger (HeapAgent)

The procedure that enables you to set a breakpoint in the debugger, use the HeapAgent browsers, then resume the debug session is given in HeapAgent Online Help (see Using HeapAgent while a process is suspended in the debugger). Unfortunately the Debug > Threads > Suspend/Resume command doesn't work very well in VC 5 (whether or not HeapAgent is present or running). This is a bug in VC 5 for which there is no workaround that we're aware of.

Analyzing data in error reports

Each error detected by HeapAgent/SmartHeap is a discrete event, and there is no facility to relate one error to another. With HeapAgent you can filter leakage reports according to a variety of criteria: see the Find leakage... selection under the Debug menu. You can also view a list of all the errors HeapAgent has detected in the error browser (select Errors under the Browse menu).

With HeapAgent 6 and later, data in the error browser (and all the other browsers as well) can be exported to spreadsheet program for analysis.

It may also be possible to grab the raw data you want using the HeapAgent API, then manipulate and format it as desired. See some of the HeapAgent specific entries in this FAQ for additional info. See the HeapAgent User's Guide or the SmartHeap Programmer's Guide for additional info.


Leakage reports? (HeapAgent)

HeapAgent will indeed falsely report leaks from DLLs that terminate *after* the HeapAgent DLL has terminated, because HeapAgent leakage reporting occurs during HeapAgent DLL termination. The problem is that there is no way to control when the OS terminates dynamically loaded DLLs that are not explicitly unloaded.

You can easily suppress the leaks if that is an acceptable workaround: simply specify a module name of your DLL in the HeapAgent suppress dialog box and indicate error type of leakage. Alternatively, if you want HeapAgent to be guaranteed to terminate after your DLL and thus detect true leakage in the DLL, it is necessary to link your DLL with the HeapAgent library. The OS will then terminate the HeapAgent DLL after terminating your DLL rather than (potentially) vice versa.

Occasionally you may see "leaks" reported for allocations created in the CRT DLL, because the CRT DLL will generally terminate later than the HeapAgent DLL. Just suppress these leaks. Many CRT "leaks" are suppressed by default in HeapAgent.


Suppressing Error Reports in debug builds

Only HeapAgent can suppress error reports. If an app is linked to debug SmartHeap and a copy of HeapAgent is installed, HeapAgent can be used to suppress error reports in the SmartHeap app. Debug SmartHeap alone does not offer the option of selectively suppressing error reports (it is possible to suppress all errors -- see the relevant FAQ entry).

Generally the easiest way to suppress errors with HeapAgent is to click on the "Suppress" button in the error windows when the error is reported. This will take you to the error suppression dialog. By default the "Persistent" box in the lower right hand corner will be checked. Clicking OK will add this error to the list of errors that HeapAgent will not report for this app.

Note: Error suppression will take effect the next time you run the app. Error suppressions are app-specific. If for some reason you want to suppress a specific error in any application that you run under HeapAgent:

  1. open HeapAgent, do not load any programs
  2. open the error suppression dialog (in the Options menu) and add the error you want suppressed.

An optional way of suppressing leakage reports is to turn off the default leakage report for the termination agent, instrument your code with a few checkpoints, and define a new agent that checks for leakage between those checkpoints. Assuming you can modify the source code for debugging, that should not be very difficult. You will, however, need to take a little time to familiarize yourself with the procedure for using "agents". First time users of HeapAgent typically don't realize that HeapAgent only springs into action when your code executes some heap-related procedure. For example, if you set up checkpoints 3 and 4 and you want to check leakage between 3 and 4 on termination, you'll need to put a call to malloc, new, or some other heap function in you app just before it terminates. That will cause HeapAgent to check for any agents to apply, and it will run your leakage agent.


Can you use Purify on an app linked with Smartheap?

The Purify User's Guide devotes an entire chapter to the subject of using Rational Purify with custom memory managers (like SmartHeap), but the workarounds it describes basically involve modifying your code to create alternate execution paths, so that when the code is being purified the app uses CRT rather than the custom memory manager. In many cases this solution is less than ideal, but unfortunately we're not aware of any other workaround.

In most cases it is possible to purify an application that's linked to SmartHeap, but Purify will most likely report a lot (hundreds in some cases) of bogus errors (FMRs, FMWs, et al) because it misinterprets SmartHeap data structures. Purify gives you the option of suppressing certain catagories of errors, but in most cases this isn't a very good solution.

From our communications with Rational tech support about these issues, we understand their position is as follows:
1) they do not recommend using Purify with custom memory managers, but
2) if you must use a custom mem manager, follow the instructions in their User Guide for working with custom memory managers.


HeapAgent's error suppression isn't working (HeapAgent)

Two possibilities:

  1. Suppression does not take affect until the next run of the program -- the only way to suppress remaining leaks on the current run is to choose the "Skip All" button.
  2. If suppression is failing on the subsequent run, one possibility is that the callstack text is so long that it does not fit within the Suppress dialog edit control. If this is the case, you can edit the suppression callstack to include fewer callers that identify the particular allocation point. This will suppress all leaks whose callstacks contain this callstack subset. For example you could specify the following in the callstack edit box: Gettnames, Locinfo::_Gettnames to suppress all the leaks in Gettnames called by Locinfo::_Gettnames. It is also possible that, because some of your function names in the callstack edit box contain spaces, the space-delimited callstack input isn't being parsed correctly. Either way, the above subset of callstack should correctly suppress your leakage.

Using Bounds Checker on an app linked with Smartheap?

Since Bounds Checker is replacing many of the same heap APIs and SmartHeap/HA, only one (BC or SmartHeap/HA) can be used at a time.

Compatible with Win32s?

MicroQuill stopped testing Win32s compatibility when MS dropped Win32s support in VC++. Our only suggestion would be to try an older version of SmartHeap -- say version 3.01, which did have Win32s support. There were no significant features or fixes introduced since SmartHeap 3.01 that would be relevant for Win32s in any event (most of the SmartHeap 3.1/3.2/3.3 /3.4 features such as shared memory, GlobalAlloc support, etc are supported in the SmartHeap DLL version only).

SmartHeap doesn't seem to return freed memory to the OS.

SmartHeap 4 specific: Apps linked with SmartHeap 4 may exhibit similar symptoms (mem usage constantly increasing over time even though resources are being freed). This problem will potentially occur with apps that create large numbers of threads, especially if the threads are dynamically created and destroyed. The solution is to turn off the small-block allocator. For important information on disabling the small-block allocator in SmartHeap 4, please click here.

SmartHeap-SMP 4 specific: In addition to MemPoolSetSmallBlockSize it is necessary to call MemPoolSetFloor from each thread in order for memory in default pools to be returned to the OS. The reason is that SmartHeap/SMP has a default floor of 2GB in order to minimize system calls (another speed/space tradeoff).

In SmartHeap-SMP as in SmartHeap 4 these APIs need to be called from each thread (MemDefaultPool is a thread-specific variable in SmartHeap-SMP). To set both the small block size and the floor size to 0 you would use the following code:

MemPoolSetSmallBlockSize(MemDefaultPool, 0);
MemPoolSetFloor(MemDefaultPool, 0);

These APIs may exact a small performance penalty. An alternative to setting the floor to zero would be to choose a value between zero and infinity (such as 1M) for the floor so that memory is returned but not every time a page becomes free. Yet another alternative would be to call MemPoolShrink(MemDefaultPool) immediately before terminating the current thread -- this would have the same effect as changing the floor to zero. Setting small block size to zero is still necessary. Yet another alternative would be to leave the floor at the default of infinity and manually specify when memory in a pool is returned to the OS with MemPoolSetFloor/MemPoolShrink at an appropriate time, such as just before a thread terminates. Our recommendation would be to set both the small block size and the floor size to 0. If performance degrades you can consider the other options.

SmartHeap 5 specific: SmartHeap 5 (standard and SMP versions) does not return memory to the OS under any circumstances. The SmartHeap API calls described below affect how SmartHeap manages memory within the heap but has no effect on returning heap memory to the OS.

SmartHeap 5 features a new, more space efficient small block allocator, but disabling it may still result in less memory consumption, depending on the alloc pattern in a given app. Users who have upgraded to SmartHeap 5 and wish to continue using the old SBA can do so by calling MemPoolSetSmallBlockAllocator (see the SmartHeap 5 API reference for details).

The new SBA is more space efficient in part because it incurs less overhead and smaller granularity. Also, in a single-threaded app, when small blocks are freed they can be recycled for different block sizes. In multi-threaded apps and in SmartHeap-SMP, however, small blocks, once alloced and freed, can never be used for anything but subsequent allocs of the same block size. So for MT/SMP SmartHeap, the SBA is still suspect in some cases in apps whose footprints grow more than expected.

Another new API, MemPoolSetHighThreads(MemDefaultPool, FALSE) will conserve space, but the extent of the impact on space very much depends on the alloc pattern and thread concurrency of the app. If space is a problem, you could try both MemPoolSetSmallBlockSize and MemPoolSetHighThreads APIs to find the speed/space tradeoff that is right for a particular app.

SmartHeap 6 & 7 specific: In SmartHeap 6.02 and above of the SmartHeap UNIX libraries, memory used for small block allocations is not returned to the operating system (OS) until the application terminates. This is a performance optimization, as munmap (used to return small block pages) is slow on most platforms. Small block memory that is no longer in-use is recycled, which further improves performance, since SmartHeap needs to make fewer expensive calls to the OS for more memory to manage.

Because of this design, memory or address space consumption may be higher than expected. If this side-effect is considered unacceptable, SmartHeap 6.02 and later offers an API, MemProcessUseMunmap, which causes SmartHeap to aggressively use munmap to return small block pages to the OS on those platforms that support it.

Allocation requests for large blocks are handled differently. SmartHeap 6 and above defines a "large block threshold" value; blocks larger than this value are allocated directly from the OS and freed directly to the OS. This threshold value is 10 MB on most UNIX platforms, but 2 GB on HPUX and AIX. A SmartHeap API, MemProcessSetLargeBlockThreshold, can be used to modify this behavior.

Unlike SmartHeap UNIX, SmartHeap for Win32 does return free small block pages to the OS. The large block threshold on Win32 is 512 K.

On both UNIX and Win32, SmartHeap has a half-dozen or so APIs that can be used to fine-tune the speed vs. space trade-off. Please contact MicroQuill tech support for more info.


Linking with SmartHeap doesn't improve my app's performance.

Performance improvements are dependent on:
1) How intensively the app exercises heap memory management
2) The amount of memory available on the machine at runtime
SmartHeap will improve performance most when the app is mem management intensive and the machine is tight on RAM relative to the app's footprint.

There are some tips for benchmarking performance in Appendix C of the SmartHeap Programmer's Guide. The most dramatic performance results would come from using multiple pools to improve application locality and thus avoid swapping, but this particular improvement will only be noticeable in a low-memory configuration typical of end-users but not typical of developers. It might be a good idea to conduct performance tests on target end-user configurations rather than on fast development machines.

For additional info on these issues, check out the performance doc on our tech support page.


When I use the SmartHeap API, I get a compile-time error referencing "throw0" in smrtheap.hpp.

This is only known to occur in SmartHeap ver. 3.31, including earlier 3.x versions that were upgraded using the patch file from our web. The solution is to contact MicroQuill tech support for a "fixed" smrtheap.hpp file.

Missing Compiler DLLs

Debug SmartHeap/HeapAgent requires specific compiler DLLs to read VC++ debugging info:

VC++ 2.0 dbi.dll
VC++ 4.0 mspdb40.dll
VC++ 4.1/4.2 mspdb41.dll
VC++ 5.0 mspdb50.dll
VC++ 6.0 mspdb60.dll
VC++ 7.0 mspdb70.dll

These DLLs are usually installed by default in the bin directory of their respective compilers. This error message is displayed if SmartHeap/HeapAgent is loaded for an app compiled using one of the above VC++ compilers and then run on a machine where neither that compiler nor its respective pdb file is installed. The message won't identify the specific DLL you need.

To fix the problem, obtain the correct pdb file and (if necessary) copy it to a directory (like winnt\system32) where HeapAgent can find it. Alternatively, you could rebuild the project with your current compiler installation.

Re Visual C++ 6: Some earlier releases of debug SmartHeap and HeapAgent 3.x may not be able to find mspdb60.dll. Copying this file to your system directory will work around this problem, or you can contact MicroQuill re an upgrade.

Re Visual Studio .NET: At this time (3/15/03) only SmartHeap version 7 and HeapAgent 7 support pdb info in VC++ 7. Contact MicroQuill tech support if you need a pre-release copy of version 7.

 


Unable to use the SmartHeap debug API to change debug settings (Win32 only)


Many of the SmartHeap debug APIs (dbgMemSetGuardSize, et al) will not work in a Win32 app, though they do work on platforms other than Win32. On Win32, SmartHeap patching necessitates that the heap be initialized at HeapAgent DLL initialization time, so the only way to modify these values is via the HeapAgent user interface. The HeapAgent UI produces a configuration file that the HeapAgent/debug SmartHeap DLL reads before initializing any heap. On Win32, therefore, SmartHeap users need to obtain HeapAgent to get this functionality.

Linking problems (Win32 specific)

When using Visual C++ we recommend using the QuickStart procedure described at the front of the Getting Started guide to link with SmartHeap. For an MFC app, this simply involves adding one line at the very top (before any other #includes) of the file stdafx.h:

#include "shmfc.cpp"

or, if you're using SmartHeap/SMP:

#include "shmfcsmp.cpp"

For a non-MFC app, you add the source file smrtheap.c (SmartHeap/SMP users would add shsmp.c) to your project and specify the appropriate obj file in the Visual C++ link dialog. For example, for a release build using standard SmartHeap you would probably specify

.\release\smrtheap.obj

See the Getting Started guide for details. The main advantages of QuickStart are:

It's perfectly OK to link the other way, by specifying a SmartHeap lib in the link dialog, but it's not a good idea to mix the two ways of linking -- use one or the other. When not using QuickStart, if multiple definition, etc. link errors occur the fix is usually to force a symbol reference to SmartHeap. In the link dialog choose the category Input, and on the Force Symbol Reference line type

_SmartHeap_malloc

That should do it. (BTW, it's not a bad idea to force the reference anyway, as it helps insure proper linkage.).

Note: Your primary source of information on linking to Win32 SmartHeap is the SmartHeap Getting Started Guide for Win32. There is additional info here.


When is it appropriate to use the fixed size allocator?


MemAllocFS/MemFreeFS should be used only in the case where you will be repeatedly allocating and freeing the objects in question. Initialization of a memory pool for fixed size allocations is a time-consuming operation because each page allocated from the OS must be initialized with a free-list. The initial overhead of constructing the free-list is compensated by very fast alloc/free operations, but only if there are several alloc/frees for each object.

Note that in SmartHeap 3.0 and higher, malloc/MemAllocPtr are nearly as fast as MemAllocFS but without the initialization overhead.


What compilers can I use with SmartHeap for Win32 and HeapAgent?

HeapAgent 6 fully supports Microsoft Visual C++ versions 2.x, 4.x, 5.0 and 6, and Borland C++ versions 4.x (except 4.53 - see below) and 5.x, and Borland C++ Builder 4.x/5.x/6.x. HeapAgent 3.12 supports Visual C++ and Borland C++, but not Borland Builder. Users of earlier 3.x versions of HeapAgent can upgrade to version 3.12 at no cost. HeapAgent 3.x users can upgrade to HeapAgent 6 for $99. Contact support@microquill.com for more info.

SmartHeap version 6.0x for Win32 supports Microsoft Visual C++ versions 2.x, 4.x, 5.0 and 6.0, and Borland C++ versions 4.x (except 4.53 - see below) and 5.x, and Borland C++ 4.x/5.x. We have also tested and found no problems compiling and linking SmartHeap using the Intel C/C++ compiler for Win32 (an add-on for Visual C++).

SmartHeap 7 and HeapAgent 7 (to be released in late March or early April, 2003) will fully support unmanaged C/C++ builds with VC++ 7 (AKA Win2003). Most versions of SmartHeap 6 should work fine for release builds using this dev environment; the one known exception is projects that link to the MFC static lib. This latter issue is fixed only in SmartHeap ver. 6.03 and later. Debug builds are also supported, but SmartHeap 6.x is unable to access VC++ 7/Win2003 pdb info, and this will result in SmartHeap reporting addrsses rather than file and line numbers in its error reports. The workaround for this latter problem can be rather cumbersome for large projects, but it will be fixed in SmartHeap 7.

If you are using a compiler other than Visual C++, Borland C++, Borland C++ Builder or Intel C++: Most standard C/C++ compilers for Win32 are probably compatible with SmartHeap, given sufficient tweaking. However we have not done any testing with them and cannot provide technical support if you encounter problems.

Re. Borland 4.53: Borland 4.53 is actually Borland 4.51 plus a "CodeGuard" add-on from Borland. Borland 4.52 is actually an older release than Borland 4.53. Anyway, the "CodeGuard'ized" libs and DLLs in Borland 4.53 are mutually exclusive with SmartHeap libs and DLLs. SmartHeap will not work with that version of the Borland compiler.


Using unsupported compilers

MicroQuill cannot provide tech support if you are using HeapAgent with an unsupported compiler. We will try to help you if you run into problems, but that help will be limited since we are probably unfamiliar with the issues involved.

Note: Unsupported compilers may define new/delete with non-standard behavior. In that case, try the following:


 

How can I be sure that my EXE/DLL is correctly linked to SmartHeap?


Proper linking usually means
  1. Your EXE/DLL is linked with the SmartHeap library that is designed for its configuration (debug/runtime, MFC/non-MFC, etc). There are detailed instructions in the Win32 Getting Started guide to help you determine which library you should link with.
  2. When you run your EXE/DLL it is calling SmartHeap's malloc/new functions. You can verify this by choosing the linker option to generate a map file and searching the file for the symbol _SmartHeap_malloc
If you are using SmartHeap version 3.31 or later and the Visual C++ compiler you have the option of using our "Quick Start " linking procedure: Quick Start should guarantee that both of the conditions above are met. See your Getting Started guide for details.

Using the API MemInitDefaultPool in a debug build causes a linker error


Some early builds of SmartHeap 4 would generate an unresolved external symbol link error if MemInitDefaultPool was called in a debug build with MEM_DEBUG defined. The problem was in the header file smrtheap.h and it was fixed in early June, '98. SmartHeap users who experience this problem with version 4 should contact MicroQuill tech support for the fix.

MEM_BAD_POINTER


The following text is taken from Appendix B of the SmartHeap Programmer's Guide:
A MEM_BAD_POINTER error may mean a number of things:

Log file problems


For a short time there was a bug in debug SmartHeap 4 which prevented writing errors to the log file. The log file was created but empty. If you experience this problem please contact MicroQuill tech support for the fix.

No known problems with SmartHeap 5 or 6.


Defragging the heap


MemPoolShrink will compact pages of moveable memory and free all pages with no allocations, so it is possible for the moveable heap to be fluid and completely fragmentation free. However, this functionality is only available for blocks allocated with SmartHeap's handle-based API. Generally it is preferable to use the ANSI, pointer-based, or fixed-size APIs. These three are easier to use (direct pointers to memory vs. handles) and faster, because locking and memory movement are not occurring.

Calling MemPoolShrink for a pool with no moveable pages will have no effect.


Garbage collection


Garbage collection (the automatic reclaiming by the OS of memory that is no longer in use) is not available in SmartHeap, because any garbage collection implementation would significantly degrade performance.

Shared memory errors on Unix platforms


Debug builds may report an error when trying to free a shared pool. This error is benign, and does not occur in non-debug builds. Choose "Retry" to continue normally.

File & line info with Borland compilers


Beginning with version 3.4, debug SmartHeap will not report file/line info for errors associated with calls to operator delete when using the Borland compiler. In Win32 SmartHeap obtains file/line info from compiler debugging info -- but only VC++ debug info is supported, not Borland. In Smartheap 3.31 and earlier, Borland users could capture file/line info for calls to operator delete, but this capability was removed in version 3.4 because its implementation required thread-local storage, which has an OS bug that potentially corrupts static data in the app in NT 4 when used from a dynamically-loaded DLL (such as the HeapAgent DLL when auto-loaded). Thus, SmartHeap 3.4/4.x cannot give you file/line info for operator delete on apps compiled with Borland C++.

Registered users of SmartHeap 3.x/4.x/5.x can contact MicroQuill tech support and request a free copy of Smartheap 3.31, which will give info for operator delete.


Per-alloc overhead in Unix


The reason the per-alloc overhead on Unix platforms is so much higher (5 bytes vs. 1 byte or so on Intel) is because of page-alignment tricks that are possible with the Win32 system allocator and the byte-alignment imposed by RISC but not Intel.

Can't get file and line info in error reports (using VC++ compiler).

Two possibilities:
1. Missing compiler files. HeapAgent relies on two files for debugging info: <app_name>.pdb and mspdbxx.dll. Typically <app_name>.pdb is in the same directory as the EXE/DLL being debugged and mspdbxx.dll is in the compiler's bin directory. If the EXE or DLL was compiled on another machine, try copying these two files into the test machine.
2. The allocation is being created in a DLL for which you don't have source. If you can find a .PDB file laying around for those DLLs (some .PDB files are included with VC DLLs, for example) copying them around appropriately might get you some function names.

CoTaskMemAlloc

CoTaskMemAlloc is implemented in terms of HeapAlloc. Prior to version 4.0, SmartHeap replaced HeapAlloc (and the other system heap functions LocalAlloc/GlobalAlloc) with its own faster allocator on Win NT only (i.e., not Win 95). Beginning with SmartHeap version 4.0 this patching is disabled by default. Developers on NT can enable patching of HeapAlloc, etc, with a registry setting. For details, see the SmartHeap 4.0 Getting Started guide entry on "SmartHeap's automatic DLL patching". You can also access an html version of Getting Started elsewhere in this knowledge base.

To sum up, you can use the registry to enable SmartHeap patching of HeapAlloc. SmartHeap will then effectively replace CoTaskMemAlloc on NT, but not on Win95/98. Otherwise SmartHeap will not interact with calls to CoTaskMemAlloc.

Linking with Solaris

If you link your Solaris app to SmartHeap and don't see any change in performance, you may need to juggle a bit with the linker library order. Use the debugger or the Solaris system utility pstack to probe the application, and see whether it's calling malloc() in libc or MemAllocPtr() in SmartHeap.

Note: under Solaris a process can have any number of heap managers, but function symbols are bound (by default) at the process rather than at the EXE/DLL level, meaning that any references to malloc in the process will be bound to the first malloc definition that was loaded (which is the one referenced in the EXE). It is possible to build a DLL in Solaris such that it uses its private malloc defiition rather than the process definition by using a linker flag.


MemCheckPtr

MemCheckPtr will return zero when passed the object pointer of an array of objects. To illustrate:

// define an object
class B
{
public:
~B();
};
B::~B()
{
printf ("B::~B()\n");
}
// somewhere in your code...
B * pB = new B[5];
MemCheckPtr (MemDefaultPool, pB);

With an array of objects, the object pointer is usually not equivalent to the value returned by operator new -- it is an offset therein, since the compiler stores the array size at the beginning of the memory block returned by the allocator. The code above is effectively doing the following:

B * pB = new B[5];
MemCheckPtr(MemDefaultPool, &pB[1]);

which will fail in Debug SmartHeap as &pB[1] is not a pointer value returned by SmartHeap (pB is). Runtime SmartHeap does not detect the error because its checking is not as extensive as debug SmartHeap's (runtime SmartHeap detects that the pointer is part of a heap block in the indicated pool, but does not perform the slower scan of heap blocks to see if this matches the beginning vs an offset into a block).

There is another debug-only API in SmartHeap that will validate a pointer that is an offset into a heap block if that is what is desired: dbgMemCheckPtr.


SmartHeap pool size

An empty SmartHeap pool uses about 4 K of memory. This is overhead. When your program makes an allocation, SmartHeap gets a page of memory from the OS to allocate out of. The size of the page will generally vary between 4 K and 64 K, and can be set using the SmartHeap API MemPoolSetPageSize. If an app has its page size set to 64 K, then one small alloc would result in the pool consuming about 70 K.

A SmartHeap page is the smallest increment of memory that can be added to or released from the pool. In order to release a page of memory from the pool, every allocation made using that page must have been freed. Thus a 64 K page with a 10 byte allocation will be held by the pool as long as the alloc is in use.

Each SmartHeap platform has a default page size. For details, see the section on "Page tuning" at the back of the SmartHeap Getting Started guide.


Note: The default behavior of SmartHeap's small block allocator will sometimes cause a SmartHeap pool to consume more mem than is desired. This behavior can be modified using the API MemPoolSetSmallBlockSize (see the Programmer's Guide and other entries in this FAQ for more info).

MemFreeDefaultPool

There is some documentation on MemFreeDefaultPool under MemDefaultPool in the SmartHeap Programmer's Guide. It should generally not be used in apps where SmartHeap replaces malloc or new as it would free blocks in use within the CRT. A new default pool will be created on a call to malloc or new subsequent to MemFreeDefaultPool.

Error messages referencing dbgheap.c

Occasionally a user will report that an app linked with the runtime SmartHeap lib (shdw32m(t).lib or shlw32m(t).lib) crashed with the error message

Debug Assertion Failed!
program xxxx.exe
File: dbgheap.c
Line: 1011
Expression: _CrtlsValidHeapPointer(pUserData)

This error can only occur if Debug C runtime library or Debug MFC is used -- the file dbgheap.c is part of the debug VC CRT, as is the API CrtIsValidHeapPointer. So the invocation of this error in association with the Runtime SmartHeap libraries indicates a runtime/debug mismatch. Runtime SmartHeap does not support debug versions of the C runtime libraries. If your application links with the Debug C runtime library it must also link with the Debug SmartHeap library.


Is there any way to check that a pointer is at least a pointer into a valid allocation?

In Debug SmartHeap only, dbgMemCheckPtr(ptr, MEM_POINTER_HEAP, size) will check to see if ptr to ptr+size falls within a valid allocation. Enumerating the entire heap is the only way to perform the check in Runtime SmartHeap.

Is it possible to disable SmartHeap's error reporting mechanism?

If you're getting SmartHeap errors in your app and you're sure these errors are benign you can prevent SmartHeap from displaying error messages on the screen by calling the function MemSetErrorHandler with a NULL parameter. All SmartHeap APIs will then silently return error return values on failure.

Messages referencing CMemoryState

Debug SmartHeap emulates all MFC APIs except for AfxDoForAllObjects and the CMemoryState member functions. For the unsupported APIs, SmartHeap defines stubs that print error messages that point to the corresponding SmartHeap APIs offering similar functionality. The solution is to use the specificed SmartHeap function instead.

Since these MFC diagnostic classes are only available in debug builds (_DEBUG defined) this is not an issue for release builds.


Runtime SmartHeap + Debug CRT = Trouble!

If your executable (EXE or DLL) links with the runtime SmartHeap library it cannot link with the debug C Runtime library. From the SmartHeap Getting Started guide for Win32:
"Visual C++ 4.0 and higher includes debugging versions of the C runtime libraries. Debug SmartHeap supports these libraries, but Runtime SmartHeap does not. Therefore, if your application links with the Debug C runtime library, it must also link with the Debug SmartHeap library (haw32m.lib) rather than the Runtime SmartHeap library (shlw32m[t].lib or shdw32m[t].lib).

Debug SmartHeap overrides the Visual C++ functions _calloc_dbg, _realloc_dbg, _free_dbg, _msize_dbg, _expand_dbg, _CrtCheckMemory, _CrtDumpMemoryLeaks, _CrtIsValidHeapPointer, _CrtIsMemoryBlock, _CrtSetAllocHook, and _CrtSetBreakAlloc. Debug SmartHeap emulates the behavior of each of these Visual C++ routines, so you can use these routines interchangeably with Debug SmartHeap APIs."

The Runtime SmartHeap DLL and debug CRT cannot coexist in the same process. If your EXE linked with the Runtime SmartHeap DLL loads other DLLs, the EXE and any DLLs loaded by the EXE cannot use debug CRT. Conversely, if you link your DLL with the Runtime SmartHeap DLL then that DLL and all other executables in the process must not use debug CRT. If you want your exectable to be compatible with any other executable, including one that might link with Debug CRT, then your executable must statically link SmartHeap, CRT and (if needed) MFC.

VC 2 and MFC

VC 2 shipped with MFC 3. MFC 2 actually shipped with a 32-bit edition of VC 1 (which SmartHeap does not support). So if you're using MFC with the VC 2 compiler, follow the instructions for linking with MFC 3.

MemSetPatching

MemSetPatching has a couple of limitations: MemSetPatching works if exported from an EXE, and should be considered an alternative to manually editing the registry.

For more info on SmartHeap's patching, click here!


Linking the DLLs used by your EXE

If your EXE is linked with the SmartHeap DLL and the CRT DLL, it will patch the CRT. Any DLL loaded into that process that uses the CRT DLL will then of necessity also use SmartHeap. So it would not be necessary to link each DLL to SmartHeap.

Note: Only the SmartHeap DLL does any patching of DLLs. Debug SmartHeap always uses the DLL, but with release builds you have a choice. See our tech support page for more info on SmartHeap patching.


Freeing memory allocated with realloc

Blocks allocated with realloc should be released with free, even if the block was originally allocated with new

SmartHeap/SMP under Win95/Win98

SmartHeap/SMP will work on Win9x, and the SMP optimization works but not as well as on NT because Win9x doesn't provide the SMP API; however, since Win9x doesn't support SMP systems, this is moot. SmartHeap/SMP and standard SmartHeap are therefore effectively identical for Win9x.

Borland PowerPack

Neither SmartHeap nor HeapAgent supports Borland PowerPack.

File & line info in error reports

Note: If you're using Visual C++ or Borland C++, please see the entries in the FAQ specific to those compilers.
There is nothing platform- or compiler-specific about the file/line reporting mechanism in Debug SmartHeap. It is simply using ANSI C macros to pass file/line to the heap routines.

Several things can prevent SmartHeap from reporting file/line info, including bugs in your code. For example, an overwrite can scribble on stack parameters or mangle the heap such that file/line info is erased. If the problem is not caused by a bug, the following test case should help you run it down:


     #include <stdio.h>

     #include <stdlib.h>

     #include "heapagnt.h"

     

     void main()

     {

        char *x = new char;

        char *y = malloc(1);

     

        delete x;

        delete x;

        free(y);

        free(y);

     }

This code should report double-free errors and show file/line for the allocs and the frees. If file/line is missing, try the following:

  1. look at the macro-expanded output the compiler generates to ensure that it is properly expanding the calls to new to new(__FILE__, __LINE__).
  2. check a map file to ensure that SmartHeap new is being linked.
  3. Set a breakpoint at runtime to see that the compiler has passed the proper filename value to operator new(char *file, int line, size_t size).


Compatibility with Visual C++ 6.0

Only SmartHeap vers. 4.01/5.x/6.0x, later releases of HeapAgent 3.12 (ha312w32.dll date of 9/28/98) and HeapAgent 6 fully support VC 6. Registered users of earlier HeapAgent 3.x versions can upgrade HeapAgent at no cost. Contact MicroQuill tech support for more info.
Note: SmartHeap 3.x Users:
MicroQuill cannot support the use of SmartHeap 3.x with VC 6. If you use SmartHeap 3.x under VC 6 you may encounter problems in debug builds and in builds that statically link MFC. We recommend that you upgrade to the current version of SmartHeap for VC 6 compatibility. For more info please contact info@microquill.com.

Using SmartHeap in a COM Project

(revised 8/12/00)

SmartHeap should work fine in a COM project. Note, however, that in Win32 many COM functions call HeapAlloc for memory. SmartHeap version 4.x and later does not replace HeapAlloc(SmartHeap 3.3 and 3.4 do replace HeapAlloc on NT). If you want your 4.x or later version of SmartHeap to replace the system heap functions (GlobalAlloc, HeapAlloc, etc) you can enable patching of HeapAlloc via a registry setting: see the section "SmartHeap's automatic DLL patching" in our Win32 Getting Started guides for details.

Note: using the SmartHeap versions of GlobalAlloc/HeapAlloc/etc may cause problems for your application, because Microsoft system DLLs make undocumented calls to the system heap functions which the SmartHeap replacements for these functions are unable to handle. We generally would not recommend using SmartHeap's HeapAlloc replacement in complex software projects.

Even if SmartHeap is not replacing HeapAlloc, multi-threaded apps that use HeapAlloc intensively (again, COM projects are a good example) may benefit from our HeapAlloc wrapper. The HeapAlloc wrapper doesn't contain SmartHeap or implement heap; it just patches HeapAlloc and GlobalAlloc and re-directs these call to per-thread HeapAlloc heaps. Usage requires just one LoadLibrary call. If your app runs on SMP boxes this design can significantly reduce contention in the system heap.


Out-of-memory errors on Windows

SmartHeap has no upper limit on how much memory it can manage, so the limit will be that set by the OS. Typically, though, the allocation process wastes some address space, and a process will run out of address space before (sometimes well before) the heap manager has stored 2 GB of data/objects. At that point you get an Out of Memory error. It's important to remember that wasted address space does not equate to wasted physical memory.

If you have an extremely large memory pool (more than 128 MB), or if your application is so large (hundreds of megabytes) that address space is short, you should set the SmartHeap page size to 64K. This will minimize wastage of address space. The default SmartHeap page size in Win32 is 16 K. See the SmartHeap Programmer's Guide and other entries in this FAQ for additional info. Note that the page size is a per pool value,

Note: Beginning with SmartHeap version 5 the default page size is 64 K on all platforms.


NT Enterprise

If the 3 GB option is enabled on NT Enterprise, SmartHeap can access it.


How to override malloc in only one source file

To have SmartHeap override malloc in a particular source file, just include the SmartHeap header shmalloc.h. All calls to malloc/realloc/calloc/free will then be defined as macros that map to (for example) MemAllocPtr(MemDefaultPool).


How to prevent SmartHeap from replacing malloc/new

(revised 1/12/05)

If for some reason you do not want SmartHeap to replace malloc and/or new, you can remove the appropriate module(s) from a SmartHeap static library (shared/dynamic libs must be rebuilt in order to remove functions). Note that if your project links to the SmartHeap static lib, it is usually adviseable to link CRT statically as well.

To remove malloc and/or new from a Win32 static lib

To prevent SmartHeap from overriding malloc remove shmalloc.obj and shmalimp.obj from shlw32m(t).lib (or shlsmpmt.lib if using SmartHeap/SMP):

lib shlw32m(t).lib /remove:shmalloc.obj

If you remove the shmalloc object module from a SmartHeap library, you will need to define SmartHeap_malloc at file scope. For example:

int SmartHeap_malloc = 0;

To prevent SmartHeap for Windows from overriding new, remove shnew.obj, shnewimp.obj and shnewvc.obj from shlw32m(t).lib (or shlsmpmt.lib, if using SmartHeap/SMP)

lib shlw32m(t).lib /remove:shnew.obj

There is no static lib for debug SmartHeap. If you don't want debug SmartHeap to define malloc/new, do the following:

  1. Use the registry (or the HeapAgent Setup utility if you have HeapAgent) to disable patching for the entire process.
  2. Remove shmalloc.obj, shmaljmp.obj, shnew.obj and shnewjmp.obj from haw32m.lib:
    lib haw32m.lib /remove:shnew.obj /remove:shnewjmp.obj...etc
  3. If you get an unresolved external linker error, then add the following at file scope:
    extern int SmartHeap_malloc = 0;

See also the section "Compiler functions that SmartHeap overrides" in the SmartHeap Win32 Getting Started Guide.

To remove malloc and/or new from a UNIX static lib

On UNIX platforms the procedure is very similar to Win32, only the commands and the file names are different. To prevent SmartHeap from overriding malloc with the statically linked non-debug SmartHeap library:

ar d libsmartheap.a shmalloc.o

If you remove the shmalloc.o object module from a SmartHeap library, you'll need to define SmartHeap_malloc at file scope. For example:

int SmartHeap_malloc = 0;

To prevent SmartHeap from replacing new, don't link to the C++ archive lib (libsmartheapC*.a) or (if you're using SmartHeap 5 or earlier) remove the object module shnew.o.

 


MemPoolInit vs MemPoolInitFS

Every SmartHeap pool can manage both fixed and variable-sized blocks. There are (possibly empty) sub-heaps within each pool for different block types. The only difference between MemPoolInit and MemPoolInitFS is that the latter specifies at initialization the FS block size whereas the former initializes with the default FS block size; the FS block size can be changed in either case (prior to the first call to MemAllocFS) with MemPoolSetBlockSizeFS.

if you use only one block type for a given pool, no memory or other overhead will be incurred for the other block types. You can choose to use separate pools for different block types or use the same pool --- it is a matter of programmer preference.


Context Switching

There are other sources of resource contention in addition to CRT heap. All the resource contention must be eliminated in order to significantly improve CPU utilization (i.e. if all threads need to concurrently access resources A, B, and C, making resource A (heap) available to all threads concurrently is necessary but not sufficient to solve the problem).


Using CStrings

  1. Some CString functions and some helper functions are hardcoded to call MFC new. SmartHeap patches the export of MFC operator new, but calls within the MFC DLL that call another routine in the same DLL don't go through the import table, and hence don't get patched to SmartHeap. The problem occurs only in release builds and there is no workaround. (It doesn't occur in debug builds because SmartHeap can get the address of the function itself (as opposed to its entry in the DLL's export table) from debug info).
  2. In some cases CStrings, in release version, make use of CFixedAlloc objects to optimize small string allocations, and each public function member of CFixedAlloc has a CriticalSection associated with it. These critical sections can be a source of contention, which can mitigate or nullify SmartHeap's performance benefits. The fix for this is to either rewrite the offending classes using SmartHeap as the allocator (if you statically link MFC) or create a derived class that uses SmartHeap for its allocator and use 'MyCStrings' instead of CStrings.

Solaris hardware support

SmartHeap and SmartHeap/SMP 4 and 5 offer limited support for pre-SPARC 9 systems. This support requires that the application link to the SmartHeap shared library. In order to provide this support and still give good performance with SPARC 9 a SPARC 9 specific optimization was placed in a "filter" shared lib, libatomic_ultra.so. It is necessary to distribute both the SmartHeap shared lib and libatomic_ultra.so with your app to ensure that both SPARC 9 and pre-SPARC 9 systems can take advantage of SmartHeap's performance. Here's the text from the SmartHeap Getting Started Guide:

The multi-threaded version of SmartHeap implements a serialization optimization that employs a SPARC 9 instruction. In order to support pre-SPARC 9 targets, we have placed the optimization in a "filter" shared library, libatomic_ultra.so. If libatomic_ultra.so is not present at runtime, or if libsmartheap_mt.so is loaded on a pre-SPARC 9 system, SmartHeap will not use the optimization. There is no functional difference with or without libatomic_ultra.so; it is just a performance optimization that impacts only highly threaded applications.

SmartHeap 5.01 and 6.00 do not support pre-SPARC 9 systems, and libatomic_ultra.so is not used in these versions.

Note: If you statically link with SmartHeap your app will run only on SPARC 9 systems.


Compiler errors with SmartHeap for Solaris

Debug builds that define DEFINE_NEW_MACRO and compiled with the SunWorkshop C++ compiler 4.2 (and possibly others) draw a compile error when the source code uses operator new with arrays of objects. A typical error message is "libC: delete[]' does not correspond to any 'new[]". This appears to be a compiler bug as the problem occurs whether or not SmartHeap is present. The following program will exhibits the same error (compiled with simply "CC test.C"):

class CUseless { public: CUseless() { } ~CUseless() { } };

void *operator new(size_t size, int parm);
void *operator new(size_t size, int parm) { return new char[size]; }

void main() { CUseless *things; things = new (1) CUseless[10]; }

This compiler does not support placement syntax for operator new with arrays of objects. Consequently, DEFINE_NEW_MACRO cannot be used with these Sun C++ compilers, because DEFINE_NEW_MACRO uses the placement syntax to pass parms to operator new.


Two versions of the SmartHeap DLL are trying to load into the same Win32 process

This can happen when an EXE or DLL is linked to one version of SmartHeap and another (perhaps 3rd party) DLL is linked to a different version. This will generate a SmartHeap error message when the app tries to load. The reason two different versions of the SmartHeap DLL cannot be used in the same process is that they will both try to patch CRT/MFC DLLs: clearly, only one version of SH can patch the CRT DLL in a given process and there is no way SmartHeap can know which version should patch.

There are three ways to solve this:

  1. Statically link SmartHeap to either the DLL or the EXE (this solution may cause problems with bad pointers if the app uses CRT/MFC DLLs and pointers are passed between the EXE & DLL).
  2. Disable patching in the process via the registry, if the app does not use CRT/MFC DLLs and hence require patching.
  3. Binary-edit the DLL so that both the EXE and the DLL refer to the same SmartHeap DLL.

Using the HeapAlloc wrapper

Note: The HeapAlloc wrapper DLL (shsmpsys.dll) has no effect on uni-processor systems: only on SMP systems that make a lot of calls to HeapAlloc with the default process heap from multiple threads.

shsmpsys.dll should be loaded with LoadLibrary, either from the EXE or from another DLL. There is no import lib for this shsmpsys.dll because it has no exports -- it simply patches HeapAlloc, etc. in the current process. It should work regardless of when it is loaded, but the earlier the better. When shsmpsys.dll is loaded, it does a LoadLibrary on itself to prevent it from being unloaded. Thus it will remain loaded until process termination, even if it was loaded by another dynamically loaded DLL.


Using Borland C++ 5.02

We have heard from some users that apps linked to SmartHeap and built with Borland C++ 5.02 may fail to catch exceptions that ought to be caught. This may be due to the fact that BC++ changed its exception handling mechanism between versions 5.01 and 5.02, and SmartHeap 3.x and 4.x for Borland were built with 5.01.

If you believe this is a problem with your app, here is a workaround:

  1. recompile the shnew.cpp file that shipped with whatever version of SmartHeap you have, after modifying your smrtheap.hpp to define MEM_CPP_THROW and/or MEM_CPP_THROW1 appropriately for the compiler's new/delete exception syntax (see existing references to MEM_CPP_THROW[1] in shnew.cpp and smrtheap.hpp).
  2. replace shnew.obj in the SmartHeap lib you are linking with with the shnew.obj from step 1 above.

Linking SmartHeap to multiple targets in a single process

As is often the case with SmartHeap, the considerations are different in Win32 and UNIX.

Multiple targets in Win32

It is generally OK to link multiple targets (several DLLs, for example) to the SmartHeap static lib, as long as you use the same version of SmartHeap with each target. A DLL statically linked to SmartHeap has a private copy of all of SmartHeap and does not even know if other DLLs or the EXE in the process are using SmartHeap. However, even if one DLL is freeing memory allocated by the other, SmartHeap will find the pool from the pointer passed in (not from a global variable), so there should be no problem.

Note: It is generally not adviseable to use the SmartHeap static libs if other modules in your app are using CRT or MFC in a DLL. See the SmartHeap Getting Started Guide for Win32 (the section "SmartHeap's Automatic DLL Patching") for more info. Also see the doc on SmartHeap patching on the tech support page of this web site.

It is OK to link multiple targets to the SmartHeap dynamic lib, as long as all targets use the same version of the lib (i.e., they must all call the same SmartHeap DLL). However, because the SmartHeap DLL patches CRT and MFC DLLs, it is generally unnecessary to do so. In other words, if you have an EXE and a lot of DLLs, and you want SmartHeap to manage memory for the entire process, simply link your EXE (or a single DLL) to the SmartHeap dynamic lib (either shdw32m(t).lib or shdsmpmt.lib). When your EXE loads SmartHeap will patch CRT/MFC heap functions and henceforth all DLLs loaded by the process will use SmartHeap automatically. Please see the Getting Started Guide and the SmartHeap patching doc on the tech support page of this web site for additional important info

Note: In SmartHeap 4.x and 5.0 every target linked to the SmartHeap DLL got its own default pool. If one of these DLLs was unloaded before the process terminated it's default pool would persist. If the same DLL was later reloaded, a new default pool would be created. In some applications (web servers, for instance) where a DLL could be unloaded/reloaded thousands of times, this behavior could create a very significant memory leak. Beginning in SmartHeap 5.01, all the modules linked to the SmartHeap DLL share a single default pool.

Multiple targets in UNIX

It is generally OK to link multiple targets to either the SmartHeap static or dynamic libs, as long as you use the same version of SmartHeap with each target. See the "Platform notes" section of your Getting Started Guide for info on any platform-specific issues.

HeapAgent's statistics browser

The HeapAgent Total Memory used by application figure is obtained by enumerating all virtual objects in the target process and summing all regions with a MEM_COMMIT attribute. This is the total amount of memory currently allocated by the process.

The figures in task man are VM Size (same a perf mon private bytes): this is the total non-shared memory in the process, which includes all heap (except SmartHeap shared pools) and other non-shared data. Code is shared so it isn't included in this figure. Neither is other shared mem. The other figure in task man is "Mem Usage", which is physical memory currently allocated to the process (i.e. RAM). The other figure in perf mon is "virtual bytes" which is address space, which isn't memory at all. This number should match the Address space used by application in the HeapAgent statistics browser.


Linking to MFC when not using precompiled headers

If your MFC project does not use precompiled headers, here's how to use the 'Quick Start' linking procedure:

  1. Add the file shmfc.cpp (or shmfcsmp.cpp for SmartHeap/SMP) to your project.
  2. Put ./release/shmfc.obj (./release/shmfcsmp.cpp for SmartHeap/SMP) as the first entry on the Object/library modules line in the link dialog.
  3. Rebuild all

RE Error message: "HeapAgent trial has expired"

If you install a full version of HeapAgent (or debug SmartHeap) but cannot run it because you get a message saying the the HeapAgent trial has expired, do the following:


Make SH6 behave like SH5

SmartHeap 5 and SmartHeap 6 use different locking mechanisms and there is no way to make SH6 behave like SH5 in this regard. However, the large-block allocator is essentially the same except that it returns memory to the OS by default in SH6, which can have a performance impact with some allocation patterns.

To closely emulate SH 5 in SH6 we suggest the following settings:


Problems with GDI Functions

GDI functions may faile when operating on a large block allocated by SmartHeap, when that block straddles two adjacent VirtualAlloc ranges. Say, for example, you're creating a bunch of 300K bitmaps. SmartHeap gets 1MB from VirtualAlloc and allocates 3 of your
300K objects out of that. For the fourth object it allocates another 1MB, and this object will straddle those two 1MB ranges. The data for the
fourth object is written into the pointer block with no problem, but if you call a GDI function on the block it may fail.

We suspect this may be a bug in the GDI function. Most likely, the GDI routine is using VirtualQuery to validate the pointer, but it is failing to take into account the adjacent VirtualAlloc object. It is not related to physical memory mapping as virtual memory is mapped to physical memory in non-contiguous 4K units -- VirtualAlloc objects do not represent contiguous blocks of physical memory.

There are several ways to work around this problem:


Problems linking to modules using MFC results in link errors

Versions of Win32 SmartHeap earlier than version 6.02 treated __stdcall CObject::delete(void *, void *) (which was introduced in VC++ 6 MFC) incorrectly. This could result in link errors similar to this:

shdsmpmt.lib(shmaljmp.obj) : error LNK2005: "public: static void __stdcall CObject::operator delete(void *,void *)" (??3CObject@@SGXPAX0@Z) already defined in XXX.lib(YYY.obj)

All SmartHeap Win32 libs built on 11/1/2001 (ver. 6.02) or later contain the fix for this problem.


May need to recompile when upgrading to SmartHeap 6.02 or later

In SmartHeap 6.02 the type of the size parameters and return values to all SmartHeap APIs changed from unsigned long to size_t. This was necessitated by Win64, where size_t is larger than unsigned long.

size_t and unsigned long are the same size in Win32 so a recompile isn't generally necessary, except that SmartHeap-specific overloaded operator new variants that took unsigned long now take size_t and the mangled names are different. So if you see the following link error you will need to recompile source files that include smrtheap.hpp:

tcall.obj : error LNK2001: unresolved external symbol "void * __cdecl shi_New(unsigned long,unsigned int,struct _SHI_Pool *)" (?shi_New@@YAPAXKIPAU_SHI_Pool@@@Z)


The evolution of SmartHeap 6 & 7

Whereas SmartHeap 5.0x never returned memory to the OS until process termination, SmartHeap 6 introduced three new APIs which give the programmer the ability to control when memory is returned and how much is returned. The default settings strike a balance between memory footprint and performance (i.e., speed) that will be suitable for most applications.

In most cases SmartHeap 6.0x also provides better absolute speed than SmartHeap 5.x.

Win32 SmartHeap 6.0x includes support for Borland C++ Builder.

What changed from SmartHeap 6.00 to 6.02

The main difference for Win32 is further space optimizations, with the page size going back to 64K (16K in SH 6.00). The small blockallocator uses 4K pages that grow dynamically to 64K. The result is that the small block allocator uses less memory, larger blocks can be sub-allocated in the medium block allocator, and largeblocks use less memory because their size is rounded to a 4K rather than 64K multiple.

SmartHeap/SMP scaling is improved, particularly on higher processor counts -- SH 6.02 scales linearly up to 64 processors.

Performance of the SmartHeap multithreaded runtime libs is improved.

The handle-based API (MemAlloc) is no longer supported in SmartHeap/SMP, which makes some further SMP speed optimizations possible.

There is also a new API: MemAllocAligned, introduced primarily for the benefit of UNIX valloc and memalign.

Several new "tuning APIs" have been added to give additional controls over when memory is returned to the OS and how much is returned.

On Win32, SmartHeap supports the Visual Studio .NET compiler in unmanaged C/C++ projects. However, the new pdb format is not supported, so

And there are a number of minor bug fixes.

What changed from SmartHeap 6.02 to 6.03

The main difference for Win32 is improved support for VC++ 7. The known linking problems have now been resolved. There is also a new API, MemProcessCoelesceSystemAllocs, to prevent SmartHeap from coelesceing blocks obtained from the OS in order to satisfy requests for large blocks of memory. This API was developed specifically to work around a bug in the Microsoft GDI.

SmartHeap UNIX has additional space optimizations. More memory and address space is returned to the OS when no longer in use, and there is a new API (MemProcessUseMunmap) to aggressively return address space on Solaris, DEC UNIX and SGI.

On both Win32 and UNIX the default sub-alloc threshold was raised from 16K to a little under 64K. This design should use less memory in most cases, and particularly when a lot of blocks in the range of 16K to 64K are allocated. A new API (MemPoolSetMaxSubAlloc) lets the user tune the suballoc threshold when appropriate.

And there are a number of minor bug fixes.

What changed from SmartHeap 6.03 to 7.00:

The noteable changes are in Win32 and Win64. All the known compatability problems with the Visual Studio .NET/VC++ 7 have been fixed. Debug SmartHeap now obtains file and line numbers for error reports transparently from the debug info generated by Microsoft compilers. Multithreaded SmartHeap and SmartHeap/SMP both support Intel's new hyperthreading technology.
On UNIX, SmartHeap for linux also supports hyperthreading.
And there are a few minor bug fixes.

 


Adapting SmarHeap to support C++-style exceptions

SmartHeap does not throw exceptions. If your application is linked to SmartHeap and you want it to throw exceptions when SmartHeap detects a heap error you should write an error-handling routine and call the SmartHeap API MemSetErrorHandler to establish it. From this custom error handler you can throw the desired exception.

For more information on how to customize error handling see the reference on MemSetErrorHandler in Chapter 4 of the SmartHeap Programmer's Guide.


One thread can free memory allocated by another thread

We get asked this question occasionally. Multithreaded SmartHeap can easily handle a situation where one thread frees memory that was allocated by a different thread. There's no performance penalty involved.


Support for moveable memory

SmartHeap 6 & 7 don't support moveable memory. If you link to SmartHeap 6 or 7 and call a moveable mem API (MemAlloc, for example) you will get a MEM_UNSUPPORTED error.

If you don't need moveable memory we would suggest that you use MemAllocPtr rather than MemAlloc. MemAllocPtr provides faster allocations and eliminates the need for you to deal with memory handles.


Controlling page alignment


SmartHeap allocates its pages (and large blocks) on 64K boundaries. The pointers SmartHeap returns to the user are not on 64K boundaries because SmartHeap stores header info in the first few bytes of pages and large blocks.

SmartHeap 6 includes an API, MemAllocAligned, which will return memory aligned on any boundary desired. SmartHeap also defines the UNIX equivalents valloc and memalign, and on Win32 the VC++ 7 CRT equivalents _aligned_malloc and _aligned_offset_malloc.

 

Controlling block alignment

The ANSI standard specifies that malloc and new return memory suitably aligned for any object, but SmartHeap versions 5.x, 6.x, 7.01, and 7.1 potentially return non-aligned memory in order to conserve space. Specifically, SmartHeap’s small block allocator (SBA) aligns on a word multiple. The first SBA block in a page is aligned on a double boundary, but subsequent blocks are aligned on a word multiple. So on a 32-bit architecture, a 4 byte SBA request will return 4-byte aligned, but an 8 byte request will return 8 byte aligned memory. Typically, compilers pad structures that contain doubles to a double multiple, so doubles will generally be suitably aligned even with SBA. However, this isn't guaranteed.

In order to guarantee sizeof(double) alignment, you must disable the SBA. SmartHeap’s medium and large blocks always align on double boundaries.
To disable the SBA use the following call:
#include <smrtheap.h> MemPoolSetSmallBlockAllocator(MemDefaultPool,
MEM_POOL_SMALL_BLOCK_NONE);

Note: Beginning with version 7.2, SmartHeap returns memory aligned as per the ANSI standard..

How many lines in SmartHeap source?

Lines of source code In SmartHeap version 7:

Aggregate SmartHeap source is a sum of all the above numbers, or ~134K SmartHeap + 75K HeapAgent.

Support for 3gb switch in Windows

If your version of the Windows OS supports the /3GB boot option, SmartHeap will be able to us the extra space.

Two sets of debug libraries

Note: This information applies to SmartHeap/SMP only.

The SmartHeap/SMP runtime heap is designed so that multiple threads can perform heap operations concurrently.This can lead to significant performance improvements, but it can also expose subtle timing bugs in your code; bugs that would never manifest in a conventional heap design, where thread access is serialized. Because debug SmartHeap serializes thread access as well, it likely won't detect these bugs. For the same reason, if you remove SmartHeap/SMP from your runtime build, the problem will probably go away.

To address this, all of our SmartHeap/SMP distributions include a special set of debug-smp libraries, designed to be used in cases where all the following are true:

The debug-smp libs are hybrids: like the runtime smp libs they allow concurrent thread access to the heap; like the debug libs they have some bug detection code. Use them as you would the SmartHeap runtime libs. UNIX users should not define MEM_DEBUG or DEFINE_NEW_MACRO on the compiler command line when using these libs.

naming conventions are different on Windows and UNIX. On Windows, the specialized smp debug libs are named sh?smpmtd.lib, where '?' is either "d" ( the dynamic lib) or "l" ('el', the static lib). On UNIX they are libsmartheap*smpd.*

For general purpose debugging, use the regular SmartHeap debug libs. They detect many more error conditions, and they provide more information for easier debugging.

For more info on this topic, see the SmartHeap/SMP Getting Started Guide for your platform, and email questions to support@microquill.com.


Linking Problems associated with older Borland compilers

If you try to link SmartHeap 6 or later to your project with an older Borland tool (Borland C++ 5.x or early versions of C++ Builder) you may see a linker error about a missing library. For example:

Error: Unable to open file 'STLP.LIB'

This is because we build the SmartHeap for Borland libs with C++ Builder 6, and Builder 6 uses these libs. If you encounter this problem, contact MicroQuill tech support.


SmartHeap and very large objects -- controlling fragmentation

The main cause of fragmentation is large requests that cannot be satisfied due to heap space being splintered into small free spaces.
if you have 1MB or greater blocks and you want to avoid fragmenting the entire address space with blocks smaller than this, SmartHeap may help. If the SmartHeap large block threshold (LBT) is set to 1MB then these large requests will occur top-down from high in the address space while all smaller requests will be handled bottom-up from low in the address space. The space in the middle is thus retained free and the high address space is never splintered by small blocks. (many operating systems, including Microsoft Windows, allocate everything starting low in the address space and the entire address space can become fragmented with interleaved large/small requests).

One caveat is that if there are many > 1MB blocks of different sizes that come and go, then the high address space can become fragmented. Tuning the LBT value for optimum space utilization would help here and this is very app-specific.

RE the LBT: this value is 512K by default in Microsoft Windows, and 10 MB on most UNIX platforms. It can be changed by calling the SmartHeap API MemProcessSetLargeBlockThreshold.


SmartHeap and very large objects -- improving performance (speed)

By default, blocks larger than SmartHeap's "large block threshold" (512K on Windows, 10MB on UNIX) are allocated by the OS and freed directly to the OS, though SmartHeap controls their location in the process's address space. You can change the large block threshold by calling the SmartHeap API MemProcessSetLargeBlockThreshold.

Larger values for the large block threshold generally result in better performance but potentially larger process footprint


DLLs linked to SmartHeap static library may "leak"

A Dynamically loaded DLL that links to a SmartHeap static library may appear to "leak" memory if both of the following conditions are met:

  1. The SmartHeap static library is added to the link command line directly (or via the Visual Studio linker dialogs) rather than indirectly via the 'Quick Start' procedure described in the SmartHeap Getting Started Guide
  2. The DLL is repeatedly unloaded and reloaded during the lifetime of the process.

What happens is, when the DLL unloads the SmartHeap default pool is not destroyed (because some allocs may still be in use), and when the DLL is reloaded SmartHeap creates a *new* default pool. This legacy of old default pools constitutes the leak.

To avoid this problem do one of the following:

  1. In your DLL project, define DllMain rather than DllEntryPoint, and link to SmartHeap via the 'Quick Start' procedure described at the front of the Getting Started Guide
  2. Explicitly link to the SmartHeap lib and add the SmartHeap source file dllexit.c to your DLL project source. Contact MicroQuill tech support (support@microquill.com) to obtain a copy of dllexit.c.

Note that the above procedures were developed in May, 2003. If your SmartHeap libraries were released before that date, contact MicroQuill tech support for updated Quick Start files and/or dllexit.c.