Chapter 3

Memory Allocation

MzScheme uses both malloc and allocation functions provided the conservative garbage collector. Embedding/extension C/C++ code may use either allocation method, keeping in mind that pointers to garbage-collectable blocks in malloced memory are invisible (i.e., such pointers will not prevent the block from being garbage-collected).

The garbage collector normally only recognizes pointers to the beginning of allocated objects. Thus, a pointer into the middle of a GC-allocated string will normally not keep the string from being collected. The exception to this rule is that pointers saved on the stack or in registers may point to the middle of a collectable object. Thus, it is safe to loop over an array by incrementing a local pointer variable.

The collector allocation functions are:

If a MzScheme extension stores Scheme pointers in a global or static variable, then that variable must be registered with scheme_register_extension_global; this makes the pointer visible to the garbage collector. Registered variables need not contain a collectable pointer at all times.

No registration is needed for the global or static variables of an embedding program, unless it calls scheme_set_stack_base with a non-zero second argument. In that case, global and static variables containg collectable pointers must be registered with scheme_register_static. The MZ_REGISTER_STATIC macro takes any variable name and registers it with scheme_register_static. The scheme_register_static function can be safely called even when it's not needed, but it should not be called multiple times for a single memory address.

Collectable memory can be temporarily locked from collection by using the reference-counting function scheme_dont_gc_ptr.

3.1  Library Functions

¤ void * scheme_malloc(size_t n)

Allocates n bytes of collectable memory.

¤ void * scheme_malloc_atomic(size_t n)

Allocates n bytes of collectable memory containing no pointers visible to the garbage collector.

¤ void * scheme_malloc_uncollectable(size_t n)

Allocates n bytes of uncollectable memory.

¤ void * scheme_malloc_eternal(size_t n)

Allocates uncollectable atomic memory. This function is equivalent to malloc except that it the memory cannot be freed.

¤ void * scheme_calloc(size_t num, size_t size)

Allocates num * size bytes of memory.

¤ char * scheme_strdup(char *str)

Copies the null-terminated string str; the copy is collectable.

¤ char * scheme_strdup_eternal(char *str)

Copies the null-terminated string str; the copy will never be freed.

¤ void * scheme_malloc_fail_ok(void *(*mallocf)(size_t size), size_t size)

Attempts to allocate size bytes using mallocf. If the allocation fails, the exn:misc:out-of-memory exception is raised.

¤ void scheme_register_extension_global(void *ptr, long size)

Registers an extension's global variable that can contain Scheme pointers. The address of the global is given in ptr, and its size in bytes in size. This function can actually be used to register any permanent memory that the collector would otherwise treat as atomic.

¤ void scheme_set_stack_base(void *stack_addr, int no_auto_statics)

Overrides the GC's auto-determined stack base, and/or disables the GC's automatic traversal of global and static variables. If stack_addr is NULL, the stack base determined by the GC is used. Otherwise, it should be the ``deepest'' memory address on the stack where a collectable pointer might be stored. This function should be called only once, and before any other scheme_ function is called.

The following example shows a typical use for setting the stack base:

    int main(int argc, char **argv) {
       int dummy;
       scheme_set_stack_base(&dummy, 0);
       real_main(argc, argv); /* calls scheme_basic_env(), etc. */
    }

¤ void scheme_register_static(void *ptr, long size)

Like scheme_register_extension_global, for use in embedding applications in situations where the collector does not automatically find static variables (i.e., when scheme_set_stck_base has been called with a non-zero second argument).

The macro MZ_REGISTER_STATIC can be used directly on a static variable. It expands to a comment if statics need not be registered, and a call to scheme_register_static (with the address of the static variable) otherwise.

¤ void scheme_weak_reference(void **p)

Registers the pointer *p as a weak pointer; when no other (non-weak) pointers reference the same memory as *p references, then *p will be set to NULL by the garbage collector. The value in *p may change, but the pointer remains weak with respect to the value of *p at the time p was registered.

¤ void scheme_weak_reference_indirect(void **p, void *v)

Like scheme_weak_reference, but *p is cleared (regardless of its value) when there are no references to v.

¤ void scheme_register_finalizer(void *p, void (*f)(void *p, void *data), void *data,
   void (**oldf)(void *p, void *data), void **olddata)

Registers a callback function to be invoked when the memory p would otherwise be garbage-collected. The f argument is the callback function; when it is called, it will be passed the value p and the data pointer data; data can be anything -- it is only passed on to the callback function. If oldf and olddata are not NULL, then *oldf and *olddata are filled with with old callback information (f and data will override ths old callback).

Note: registering a callback not only keeps p from collection until the callback is invoked, but it also keeps data from collection.

¤ void scheme_add_finalizer(void *p, void (*f)(void *p, void *data), void *data)

Adds a finalizer to a chain of primitive finalizers. This chain is separate from the single finalizer installed with scheme_register_finalizer; all finalizers in the chain are called immediately after a finalizer that is installed with scheme_register_finalizer.

See scheme_register_finalizer, above, for information about the arguments.

¤ void scheme_add_scheme_finalizer(void *p, void (*f)(void *p, void *data), void *data)

Installs a ``will''-like finalizer, similar to will-register. Scheme finalizers are called one at a time, requiring the collector to prove that a value has become inaccesibile again before calling the next Scheme finalizer.

See scheme_register_finalizer, above, for information about the arguments.

¤ void scheme_dont_gc_ptr(void *p)

Keeps the collectable block p from garbage collection. Use this procedure when a reference to p is be stored somewhere inaccessible to the collector. Once the reference is no longer used from the inaccessible region, de-register the lock with scheme_gc_ptr_ok.

This function keeps a reference count on the pointers it registers, so two calls to scheme_dont_gc_ptr for the same p should be balanced with two calls to scheme_gc_ptr_ok.

¤ void scheme_gc_ptr_ok(void *p)

See scheme_dont_gc_ptr.

¤ void scheme_collect_garbage()

Forces an immediate garbage-collection.