This part of the manual covers one of the central
features of the system runtime. It requires some basic understanding of C. If
you are a beginner, skip this chapter and remember: To get more memory, use the function GC_malloc(), and forget the rest. No free() or other
items are required.
Lcc-win32 features the garbage collector developed
by Hans J. Boehm and Alan J. Demers. This fine piece of public software allows
you to program in C from a different, much more relaxed perspective.
The well-known
problem with manual memory management is that it is very difficult for a person
to specify without any error when each memory block used will be destroyed and
recycled by the runtime system.
This is a task that
is better left to a machine, i.e., a computer. The authors of this software
have solved the memory management problem, eliminating countless debugging
hours.
There are, of
course, applications where real-time requirements make the usage of the
automatic memory manager impossible. Those applications can still use the
default memory manager (a much slower solution) or devise a memory manager
tailored to the application, as all C programmers do, in one way or another.
For most
applications, however, the time required for the memory manager to accomplish
its task will be unnoticeable. The authors’ years of development have fine
tuned the software. The speed of the automatic memory manager exceeds that of
the standard “malloc” implementation by a factor of greater than 10!
The development speed is another important factor.
You can concentrate more on what the program is doing and if its doing it well
now without having to focus on each bit of RAM you are using. It is no longer
necessary to develop a memory manager for each application. A DLL and a link
time import library are the only requirements.
The debugging time
required by manual collection must also be taken into consideration. Problems
in this area are quite difficult to locate. A memory leak or a mistake like
calling free twice can cause a long search and hours lost in the debugger. If
you ever find the problem at all. There are numerous examples of programs with
this type of problem that are never corrected: it is just too hard to follow.
When the symptoms appear, there is a crash, etc., the real problem can be far
removed. Reconstructing the route from the destroyed data to the error can take
an immense amount of time.
Consider too, the
realities of the lcc-win32 implementation. The malloc runtime function
furnished with the Windows system is quite possibly the worst implementation
available. When compiled for the standard memory allocator, Wedit takes 80
seconds to load an 8 MB project. This time is reduced to only 5 seconds with
the collector.
You should know,
however, that the memory manager requires a few simple rules to operate
properly. These rules are common sense, so they are easy to understand and
follow.
Below are a few simple rules to follow when using the
memory manager.
1.
Never store pointers to
objects allocated with the collector in inaccessible places. For instance:
·
Do not store pointers in
the window extra bytes, without keeping a pointer somewhere in memory to
indicate to the collector which object is being used. The memory manager has no
access to pointers inside the system’s data structures. It will therefore
assume that memory can be reclaimed, resulting in problems in your program.
·
Do not store pointers at odd
addresses or at addresses that are not a multiple of four. The compiler and
the linker align the memory so that this is the case for all your data
when the program starts. Thereafter, you must follow this rule.
2.
Do not store pointers in
arrays declared as integers or in DWORDs. The compiler generates type
information and makes special calls to the memory manager when the object
allocated contains no pointers. Basically, it tells the collector to ignore
those memory locations, since they do not contain pointers. If you circumvent
this with casts, the collector will not know that the data are being used and
will reclaim them.
3.
It is better, though not
required, to set all pointers that are no longer is use to ZERO to avoid
retaining too much data unnecessarily. If you do not do this, the data will be
retained until the scope of the pointer is finished. Pointers stored in global
variables remain indefinitely, so that the data they point to will never be
reclaimed and the program will leak. A similar situation holds for pointers
stored as local variables in the main() function
4.
You should link with
gc.lib, which is the import library of gc.dll. For technical reasons, it is not
possible to link statically with the gc. It must be a DLL. This means that when you ship your program, it must
be shipped with the gc.dll .[1]
This interface is described in greater detail in the on-line documentation. It will not be repeated here. You can find it if you go to the « index » item in the help menu, and choose the memory manager link.
Function |
Description |
void *GC_malloc(size_t size) ; |
Returns to the address of a new memory block start. The object can contain pointers to other objects. |
void * GC_malloc_atomic(size_t size) ; |
Returns to the address of a new memory block start, which cannot contain pointers. |
void *GC_realloc(void *oldObject,size_t newSize) ; |
Resizes the given object. |
void *GC_malloc_ignore_off_page( size_t) ; |
Large objects (> 100K) should be allocated using this function. |
size_t GC_size(void *object) ; |
Returns the size in bytes of the given object. |
[1] The memory manager must be informed by the
system when the program starts a new thread. The stack of the new thread must be
recorded. This is not possible with a static library. The collector data
structures are protected with semaphores, but the collector must stop all other
threads to avoid being called when a collection is not finished.