summaryrefslogtreecommitdiff
path: root/docs/simple_example.md
blob: 9753d823bd69f243bda3d820bb560efcabc27931 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# Using the Garbage Collector: A simple example

The following consists of step-by-step instructions for building and using the
collector. We'll assume a Linux/gcc platform and a single-threaded
application. The green text contains information about other platforms
or scenarios. It can be skipped, especially on first reading.

## Building the collector

If you have not so yet, unpack the collector and enter the newly created
directory with:


    tar xvfz gc-<version>.tar.gz
    cd gc-<version>


You can configure, build, and install the collector in a private directory,
say /home/xyz/gc, with the following commands:


    ./configure --prefix=/home/xyz/gc --disable-threads
    make
    make check
    make install


Here the `make check` command is optional, but highly recommended. It runs
a basic correctness test which usually takes well under a minute.

### Other platforms

On non-Unix, non-Linux platforms, the collector is usually built by copying
the appropriate makefile (see the platform-specific README in `docs/platforms`
folder in the distribution) to the file `Makefile`, and then typing `make` (or
`nmake` or ...). This builds the library in the source tree. You may want
to move it and the files in the include directory to a more convenient place.

If you use a makefile that does not require running a configure script, you
should first look at the makefile, and adjust any options that are documented
there.

If your platform provides a `make` utility, that is generally preferred
to platform- and compiler- dependent "project" files. (At least that is the
strong preference of the would-be maintainer of those project files.)

### Threads

If you do not need thread support, configure the collector with:


    --disable-threads


Alternatively, if your target is a real old-fashioned uniprocessor (no
"hyperthreading", etc.), you may just want to turn off parallel marking with
`--disable-parallel-mark`.

### C++

You will need to include the C++ support, which unfortunately tends to be
among the least portable parts of the collector, since it seems to rely
on some corner cases of the language. On Linux, it suffices to add
`--enable-cplusplus` to the configure options.

## Writing the program

You will need to include "gc.h" at the beginning of every file that allocates
memory through the garbage collector. Call `GC_MALLOC` wherever you would have
call `malloc`. This initializes memory to zero like `calloc`; there is no need
to explicitly clear the result.

If you know that an object will not contain pointers to the garbage-collected
heap, and you don't need it to be initialized, call `GC_MALLOC_ATOMIC`
instead.

A function `GC_FREE` is provided but need not be called. For very small
objects, your program will probably perform better if you do not call it, and
let the collector do its job.

A `GC_REALLOC` function behaves like the C library `realloc`. It allocates
uninitialized pointer-free memory if the original object was allocated that
way.

The following program `loop.c` is a trivial example:


    #include "gc.h"
    #include <assert.h>
    #include <stdio.h>

    int main(void) {
        int i;

        GC_INIT();
        for (i = 0; i < 10000000; ++i) {
            int **p = (int **) GC_MALLOC(sizeof(int *));
            int *q = (int *) GC_MALLOC_ATOMIC(sizeof(int));
            assert(*p == 0);
            *p = (int *) GC_REALLOC(q, 2 * sizeof(int));
            if (i % 100000 == 0)
                printf("Heap size = %lu bytes\n",
                       (unsigned long)GC_get_heap_size());
        }
        return 0;
    }


### Interaction with the system malloc

It is usually best not to mix garbage-collected allocation with the system
`malloc`-`free`. If you do, you need to be careful not to store pointers
to the garbage-collected heap in memory allocated with the system `malloc`.

### Other Platforms

On some other platforms it is necessary to call `GC_INIT` from the main
program, which is presumed to be part of the main executable, not a dynamic
library. This can never hurt, and is thus generally good practice.

### Threads

For a multi-threaded program, some more rules apply:

  * Files that either allocate through the GC _or make thread-related calls_
  should first define the macro `GC_THREADS`, and then include `gc.h`. On some
  platforms this will redefine some threads primitives, e.g. to let the
  collector keep track of thread creation.

### C++

In the case of C++, you need to be especially careful not to store pointers
to the garbage-collected heap in areas that are not traced by the collector.
The collector includes some _alternate interfaces_ to make that easier.

### Debugging

Additional debug checks can be performed by defining `GC_DEBUG` before
including `gc.h`. Additional options are available if the collector is also
built with `--enable-gc-debug` and all allocations are performed with
`GC_DEBUG` defined.

### What if I can't rewrite/recompile my program?

You may be able to build the collector with `--enable-redirect-malloc` and set
the `LD_PRELOAD` environment variable to point to the resulting library, thus
replacing the standard `malloc` with its garbage-collected counterpart. This
is rather platform dependent. See the _GC leak detection documentation_ for
some more details.

## Compiling and linking

The above application `loop.c` test program can be compiled and linked with:


    cc -I/home/xyz/gc/include loop.c /home/xyz/gc/lib/libgc.a -o loop


The `-I` option directs the compiler to the right include directory. In this
case, we list the static library directly on the compile line; the dynamic
library could have been used instead, provided we arranged for the dynamic
loader to find it, e.g. by setting `LD_LIBRARY_PATH`.

### Threads

On pthread platforms, you will of course also have to link with `-lpthread`,
and compile with any thread-safety options required by your compiler. On some
platforms, you may also need to link with `-ldl` or `-lrt`. Looking
at `tools/threadlibs.c` should give you the appropriate list if a plain
`-lpthread` does not work.

## Running the executable

The executable can of course be run normally, e.g. by typing:


    ./loop


The operation of the collector is affected by a number of environment
variables. For example, setting `GC_PRINT_STATS` produces some GC statistics
on stdout. See [README.environment](README.environment) file for the details.