Index: gc-howto-content.html =================================================================== --- gc-howto-content.html (revision 454321) +++ gc-howto-content.html (working copy) @@ -1,359 +1,139 @@ - - - - - - -How to write DRL GC - - - -
-
-

This document provides instructions on creating a custom garbage collector implementation -in C++ and configuring the DRL virtual machine to use it. The document describes -the major steps of this procedure, namely:

- -
Note
-

Plugging-in a user-designed garbage collector presupposes an operating DRL -virtual machine built according to the instructions of the README.txt file -supplied with the VM source package.

-
-
-

1. Establishing the build infrastructure

-
-

At this stage, you create the directory and set up the build infrastructure to -build the dynamic library. At the end of this stage, you will be fully set for -adding the garbage collector code and building it.

-

DRLVM can load a custom garbage collector from a dynamic library. It is -recommended that you build your dynamic library using a DRLVM build -infrastructure. Below is an example of creating of a -build descriptor on the Windows* / IA-32 architecture.

-

1.1. Create a directory for a new GC module, for example:

-
-
-
vm$ mkdir gc_copying
-vm$ mkdir gc_copying/src
-vm$ cd gc_copying/src
-
-

That is where you will put the source code, see Section 3, -Implementing the garbage collector algorithm.

-

1.2. Create a build descriptor file

-

Create the build descriptor file build/make/components/vm/gc_copying.xml -with the following content:

-
-
-
<project name="vm.gc_copying">
+                            

Create the build descriptor file + build/make/components/vm/gc_copying.xml + with the following content:

+
+<project name="vm.gc_copying">
     <target name="init" depends="common_vm">
         <property name="build.depends" value="extra.apr,vm.vmcore" />
         <property name="outtype" value="shared" />
@@ -372,7 +152,7 @@
             </includepath>
 
             <fileset dir="${src}/gc_copying/src">
-		<include name="*.cpp" />
+                <include name="*.cpp" />
             </fileset>
 
             <defineset define="BUILDING_GC" />
@@ -389,262 +169,413 @@
             </select>
         </linker>
     </target>
-</project>
-
-

You can add other macro definitions, include directories or compiler-specific -command-line options to match your needs.

-

1.3. Create a C++ file with essential includes, namely:

-
-
-
#include "open/gc.h"
+</project>
+
+ +

You can add other macro definitions, + include directories or + compiler-specific command-line options + to match your needs.

+ +

+ + 2.3 Creating a C++ file with essential + include files

+ +

Create a C++ file with essential + include files, namely:

+
+#include "open/gc.h"
 #include "open/vm_gc.h"
 #include "open/vm.h"
 
 #define LOG_DOMAIN "gc"
-#include "cxxlog.h"
-
-

These include files are located in directories vm/include/open and -vm/port/include. Consult their content for documentation and details of the -interface.

-

1.4. Test the configuration

-

Run the build system to test whether the infrastructure is set up correctly:

-
-
-
build$ build.bat -DCOMPONENTS=vm.gc_copying
-
-

On a successful build, the .dll file is placed to the VM build directory -build/win_ia32_icl_debug/deploy/jre/bin/. The name of the directory may differ -depending on your system and the compiler used. This empty library will not -work, you have to write your GC first!

-
-

2. Implementing the GC interface

-
-

This section lists the functions that a garbage collector interface must -implement. Declarations of these functions are in gc.h. For details, consult -the Developer's Guide and documentation in gc.h and vm_gc.h.

-

2.1. GC lifecycle

- -

2.5. The VM_GC interface

-

The garbage collector requires VM support in its operation. The virtual machine -exports the VM_GC interface to meet the needs of the garbage collector. -Besides, the GC uses the VM_common interface.

-

The VM_GC interface describes the services that the VM provides specifically -for the garbage collector. Please refer to the header file vm_gc.h to see the -complete list and documentation.

-

The VM exports two functions to provide the global locking service for the -garbage collector: vm_gc_lock_enum() and vm_gc_unlock_enum(). These two -functions differ from plain system locks in their ability to gracefully -interoperate with VM threading services. In case of contention on the GC lock, -that is, when multiple threads call vm_gc_lock_enum() simultaneously, one -thread gets the lock, and others remain blocked. If the thread that grabbed the GC -lock does a garbage collection, the blocked threads are considered safely -suspended. Other ways to lock user threads for a long time can lead to a -deadlock because the VM will have no way to find out whether the thread is blocked -or running.

-

A detailed description of GC procedure is given in the Developers' Guide.

-

DRLVM provides two functions to support thread suspension and root set -enumeration simultaneously:

- -

These functions effectively restrict the garbage collector to stop-the-world algorithms only.

-
-

3. Implementing the garbage collector algorithm

-
-

This section gives step-by-step instructions on how to implement the garbage -collection algorithm. The example shows a semispace copying collector.

-
Note
-

This example does not implement object finalization and weak references.

-

3.1. Algorithm Overview

-

The heap is divided into two equally sized contiguous semispaces. -During normal operation, only one semispace is used (current semispace), -and the other one is reserved for garbage collection. -Allocation requests are satisfied by contiguous allocation -from the current semispace. Each application thread reserves a thread-local -allocation buffer (TLAB) under a global lock, and serves most of the allocation -requests without locking, by incrementing the allocation pointer local -to the buffer.

-

When the application requests an allocation that does not fit into the remaining -free space of the current semispace, a garbage collection is initiated. The current -semispace becomes the evacuation space (fromspace), and the reserved semispace -becomes the destination space (tospace). The VM suspends all application threads and -enumerates root references.

-

The GC copies the objects reachable from root references to the destination space. -When an object is copied from evacuation space to destination space, the GC installs -the forwarding pointer in the old copy. Root references are updated to point -to new object locations.

-

After the root set enumeration is complete, the GC scans objects in the -destination space. Each reached object is copied to the destination space, -the forwarding pointer is installed in the old copy, and the scanned object fields are -updated. For objects with forwarding pointers installed, the GC updates object fields. -In this way, the GC ensures that all live objects are copied to the destination space exactly once.

-

The destination space serves as a queue of objects to be scanned when -more and more objects are copied to the destination space during heap -traversal. Once all live objects are reached and copied, the scan -queue stops growing, and the GC updates object fields only during -the last part of the scanning process.

-

The GC completes the scanning process when the scan pointer reaches the allocation -pointer in the destination space. At this stage, all live objects have been -evacuated to the destination space, and the evacuation space can be safely reclaimed. -The GC then changes the semispace roles: it uses the destination space for further allocation -and reserves the evacuation space for the next garbage collection. The change of -the semispace roles is commonly referred to as flip.

-

After the semispace flip, the GC resumes user threads.

-

Please refer to the excellent survey for detailed description -of this algorithm and other basic garbage collection techniques, -"Uniprocessor Garbage Collection Techniques", Paul R. Wilson.

-

3.2. Source code explained

-

The full source code of the collector is available in gc_copying.cpp.

-

The structure TLS (thread-local storage) -is used for the optimizing fast path allocation. The GC allocates -a buffer of free space from the heap with appropriate locking and further uses -this buffer for thread-local allocation.

-
-
-
// This structure is allocated for each user thread.
+                            

The destination space serves as a + queue of objects to be scanned when + more and more objects are copied to the + destination space during heap + traversal. Once all live objects are + reached and copied, the scan queue + stops growing, and the GC updates + object fields only during the last part + of the scanning process.

+ +

The GC completes the scanning + process when the scan pointer reaches + the allocation pointer in the + destination space. At this stage, all + live objects have been evacuated to the + destination space, and the evacuation + space can be safely reclaimed. The GC + then changes the semispace roles: it + uses the destination space for further + allocation and reserves the evacuation + space for the next garbage collection. + The change of the semispace roles is + commonly referred to as + flip.

+ +

After the semispace flip, the GC + resumes user threads.

+ +

Please refer to the excellent survey + for detailed description of this + algorithm and other basic garbage + collection techniques, "Uniprocessor + Garbage Collection Techniques", Paul R. + Wilson.

+ +

3.2. Source code explained

+ +

The full source code of the + collector is available in + gc_copying.cpp.

+ +

The structure TLS + (thread-local storage) is used for the + optimizing fast path allocation. The GC + allocates a buffer of free space from + the heap with appropriate locking and + further uses this buffer for + thread-local allocation.

+
+// This structure is allocated for each user thread.
 // It contains the thread-local allocation area.
 
 struct TLS {
     byte* current;  // the allocation pointer
     byte* limit;    // the end of the allocation area
-};
-
-

Define the main GC structure to contain the Java heap and the data necessary -for GC operation, as shown below.

-
-
-
// Encapsulates all GC data.
+};
+
+ +

Define the main GC structure to + contain the Java heap and the data + necessary for GC operation, as shown + below.

+
+// Encapsulates all GC data.
 struct GC {
 
     unsigned int semisize;   // the size of the semispace
@@ -687,13 +618,14 @@
 
     std::list<InteriorPointer> interior_pointers;
     void repoint_all_roots_with_interior_points();
-};
-
-

The following structure stores object information: the object field layout and -the object size.

-
-
-
// Structure OI (from "object information")
+};
+
+ +

The following structure stores + object information: the object field + layout and the object size.

+
+// Structure OI (from "object information")
 // is used to cache GC information for each Java class
 // loaded by the virtual machine.
 // Each VTable stores the pointer to an OI (Object information) structure.
@@ -707,107 +639,141 @@
     int size;           // the object size or the array element size
     int* offsets;       // zero-terminated list of slot offsets in an object
                         // undefined for array
-};
-
-

The data stored in the OI structure is initialized and accessed by the GC only.

-

The following structures convey the static assumptions that GC makes about -object layout. The VM must use the same object layout assumptions for the -correct GC operation.

-

The VTable structure contains the virtual table of the object methods, -and is linked from the object header. The VM reserves some space (at least 4 bytes) -for exclusive use by GC. The GC uses 4 bytes of GC-private space to put the pointer -to the object information structure struct OI.

-
-
-
// The VTable structure has 4 bytes reserved
+};
+
+ +

The data stored in the + OI structure is + initialized and accessed by the GC + only.

+ +

The following structures convey the + static assumptions that GC makes about + object layout. The VM must use the same + object layout assumptions for the + correct GC operation.

+ +

The VTable structure + contains the virtual table of the + object methods, and is linked from the + object header. The VM reserves some + space (at least 4 bytes) for exclusive + use by GC. The GC uses 4 bytes of + GC-private space to put the pointer to + the object information structure + struct OI.

+
+// The VTable structure has 4 bytes reserved
 // for GC use at the beginning.
 // The pointer to the OI structure is stored there.
 struct VTable {
     OI* oi;
     // Other VTable fields are not used in GC.
-};
-
-

The GC assumes that each Java* object has a fixed header: (1) a pointer -to the VTable structure, and then a (2) 32 bit word with flags. -The 25 highest bits are used by the VM Thread Manager component to -implement Java* monitors and 7 lowest bits are used by GC and for -storing the object hash code.

-
-
-
// Describes the object header format assumed by GC.
+};
+
+ +

The GC assumes that each Java object + has a fixed header: (1) a pointer to + the VTable structure, and + then a (2) 32 bit word with flags. The + 25 highest bits are used by the VM + Thread Manager component to implement + Java monitors and 7 lowest bits are + used by GC and for storing the object + hash code.

+
+// Describes the object header format assumed by GC.
 struct Object {
     VTable *vt;
     uint32 lockword;
-};
-
-

The array objects have the same header, and a 4 byte length field -at the offset 8.

-
-
-
// Describes the array header format assumed by GC.
+};
+
+ +

The array objects have the same + header, and a 4 byte length field at + the offset 8.

+
+// Describes the array header format assumed by GC.
 struct Array {
     VTable *vt;
     uint32 lockword;
     uint32 length;
-};
-
-
Note
-

The layout described is valid for the IA-32 platform only.

-

A number of convenience functions use object layout knowledge to perform -various data manipulations. The function init_vt() writes the VTable pointer -to an object.

-
-
-
void init_vt(Managed_Object_Handle p, Allocation_Handle ah) {
+};
+
+ +

Note

+ +

The layout + described is valid for the IA-32 + platform only.

+ +

A number of convenience functions + use object layout knowledge to perform + various data manipulations. The + function init_vt() writes + the VTable pointer to an object.

+
+void init_vt(Managed_Object_Handle p, Allocation_Handle ah) {
     Object* obj = (Object*)p;
     obj->vt = (VTable*)ah;
-}
-
-

The function obj_oi() retrieves object information structure -pointer from an object.

-
-
-
OI* obj_oi(Managed_Object_Handle p) {
+}
+
+ +

The function obj_oi() + retrieves object information structure + pointer from an object.

+
+OI* obj_oi(Managed_Object_Handle p) {
     Object* obj = (Object*)p;
     return obj->vt->oi;
-}
-
-

The function array_length() retrieves the length of an array -object.

-
-
-
int array_length(Managed_Object_Handle p) {
+}
+
+ +

The function + array_length() retrieves + the length of an array object.

+
+int array_length(Managed_Object_Handle p) {
     Array* array = (Array*)p;
     return array->length;
-}
-
-

The function vt_oi() retrieves the OI structure pointer -from the VTable pointer.

-
-
-
OI* vt_oi(VTable_Handle p) {
+}
+
+ +

The function vt_oi() + retrieves the OI structure + pointer from the VTable pointer.

+
+OI* vt_oi(VTable_Handle p) {
     VTable* vt = (VTable*)p;
     return vt->oi;
-}
-
-

The function ah_oi() retrieves the OI structure pointer -using Allocation_Handle. On 32-bit architectures, the -VTable pointer is a 32-bit pointer, and Allocation_Handle is a 32-bit -integer.

-
-
-
OI* ah_oi(Allocation_Handle ah) {
+}
+
+ +

The function ah_oi() + retrieves the OI structure + pointer using + Allocation_Handle. On + 32-bit architectures, the VTable + pointer is a 32-bit pointer, and + Allocation_Handle is a 32-bit + integer.

+
+OI* ah_oi(Allocation_Handle ah) {
     // Allocation_Handle is a VTable pointer on 32-bit platforms.
     return vt_oi((VTable_Handle)ah);
-}
-
-

The object_size() function computes the size of an object. Array size is -calculated by summing the header size and the element size multiplied by array -length. Afterwards the size is aligned to be multiple of 4. The non-array -object size is cached in the OI structure.

-
-
-
int object_size (Managed_Object_Handle obj) {
+}
+
+ +

The object_size() + function computes the size of an + object. Array size is calculated by + summing the header size and the element + size multiplied by array length. + Afterwards the size is aligned to be + multiple of 4. The non-array object + size is cached in the OI structure.

+
+int object_size (Managed_Object_Handle obj) {
     OI* oi = obj_oi(obj);
     if (oi->is_array) {
         // 4-byte alignment
@@ -815,29 +781,37 @@
     } else {
         return oi->size;
     }
-}
-
-

In this example, the garbage collector is created statically as a global -instance of structure GC:

-
-
-
GC gc;
-
-

The function init() statically configures size parameters. Normally, this -function uses the function vm_get_property() to read configuration options -specified as property values on the command line. In this example, we use -constant values for simplicity.

-
-
-
void GC::init() {
+}
+
+ +

In this example, the garbage + collector is created statically as a + global instance of structure GC:

+
+GC gc;
+
+ +

The function init() + statically configures size parameters. + Normally, this function uses the + function vm_get_property() + to read configuration options specified + as property values on the command line. + In this example, we use constant values + for simplicity.

+
+void GC::init() {
     semisize = 500*1024*1024;
-    chunk_size = 64*1024;
-
-

As the next step, the init() function allocates space for the heap, divides it -into two semispaces, and initializes the allocation semispace.

-
-
-
    space = (byte*) malloc(semisize*2);
+    chunk_size = 64*1024;
+
+ +

As the next step, the + init() function allocates + space for the heap, divides it into two + semispaces, and initializes the + allocation semispace.

+
+    space = (byte*) malloc(semisize*2);
     assert(space); assert(((int)space & 3) == 0);
     fromspace = space;
     tospace = fromspace + semisize; assert(((int)tospace & 3) == 0);
@@ -854,14 +828,19 @@
     memset(current, 0, limit - current);
 
     interior_pointers.clear();
-}
-
-

The global allocation function uses a lock to protect the heap from -simultaneous access from multiple threads. The locking mechanism -is trivially implemented in a platform-dependent way. See the full source code in gc_copying.cpp.

-
-
-
byte* GC::galloc(unsigned size) {
+}
+
+ +

The global allocation function uses + a lock to protect the heap from + simultaneous access from multiple + threads. The locking mechanism is + trivially implemented in a + platform-dependent way. See the full + source code in + gc_copying.cpp.

+
+byte* GC::galloc(unsigned size) {
     byte* r = NULL;
     lock.lock();
     if (current + size <= limit) {
@@ -870,15 +849,18 @@
     }
     lock.unlock();
     return r;
-}
-
-

The local allocation function uses the thread-local allocation area for object -allocation, and uses galloc() to allocate a new chunk for a thread-local -allocation area as needed.

-
-
-
byte* GC::alloc(unsigned size, TLS* tls) {
+}
+
+

The local allocation function uses + the thread-local allocation area for + object allocation, and uses + galloc() to allocate a new + chunk for a thread-local allocation + area as needed.

+
+byte* GC::alloc(unsigned size, TLS* tls) {
+
     byte* obj = NULL;
 
     assert(NULL == tls->current || fromspace <= tls->current);
@@ -907,26 +889,30 @@
     }
 
     return obj;
-}
-
-

The forwarding pointers are installed in the lockword structure, the second word -of an object.

-
-
-
byte* GC::forwarded (void* obj) {
+}
+
+ +

The forwarding pointers are + installed in the lockword structure, + the second word of an object.

+
+byte* GC::forwarded (void* obj) {
     int* p = (int*)obj + 1;
     int lockword = *p;
     if (lockword & 1)
         return (byte*)(lockword & (~1));
     else
         return NULL;
-}
-
-

The function move() copies the object data to the evacuation semispace and -installs the forwarding pointer in the old object copy.

-
-
-
byte* GC::move (void* obj) {
+}
+
+ +

The function move() + copies the object data to the + evacuation semispace and installs the + forwarding pointer in the old object + copy.

+
+byte* GC::move (void* obj) {
     int size = object_size(obj);
     assert(tospace <= copy); assert(copy + size <= toend);
 
@@ -940,15 +926,20 @@
     *plockword = ((int)nobj) | 1;
 
     return nobj;
-}
-
-

The function root() handles one root during root set enumeration. If the root -points to an object already reached, the root is updated with the forwarded -pointer value. Otherwise, the GC moves the object to the destination space and -installs the forwarding pointer in the old object copy.

-
-
-
void GC::root(void** root) {
+}
+
+ +

The function root() + handles one root during root set + enumeration. If the root points to an + object already reached, the root is + updated with the forwarded pointer + value. Otherwise, the GC moves the + object to the destination space and + installs the forwarding pointer in the + old object copy.

+
+void GC::root(void** root) {
     byte* obj = (byte*)(*root);
     byte* nobj = forwarded(obj);
     if (NULL == nobj) {
@@ -957,12 +948,13 @@
     TRACE2("gc.root", "root " << root << " repointed from "
             << (void*)obj << " to " << (void*)nobj);
     *root = nobj;
-}
-
-

The function trace() scans one object.

-
-
-
void GC::trace (byte* obj) {
+}
+
+ +

The function trace() + scans one object.

+
+void GC::trace (byte* obj) {
     OI* oi = obj_oi(obj);
     TRACE2("gc.trace", "trace " << (void*)obj
         << " (" << (void*)object_size(obj) << ", " << oi->name << ")");
@@ -998,22 +990,36 @@
             *field = nobj;
         }
     }
-}
-
-

The function collect_alloc() is the main function controlling garbage -collection. This function reclaims unused memory and the retries the allocation. The GC -attempts to allocate the memory before resuming other threads. This prevents the -thread that triggered the garbage collection from starving.

-
Note
-

The thread is starving when it gets no resources for a long time -because other threads grab the resource before it can even try. -If the garbage collector resumes user threads before retrying the allocation, -these threads may use all available space quickly before the allocation succeeds. -In this case, the allocation will fail for an indefinite number of times.

-
-
-
byte* GC::collect_alloc(unsigned size, TLS* tls) {
+}
+
+

The function + collect_alloc() is the + main function controlling garbage + collection. This function reclaims + unused memory and the retries the + allocation. The GC attempts to allocate + the memory before resuming other + threads. This prevents the thread that + triggered the garbage collection from + starving.

+ +

Note

+ +

The thread is + starving when it gets no + resources for a long time because other + threads grab the resource before it can + even try. If the garbage collector + resumes user threads before retrying + the allocation, these threads may use + all available space quickly before the + allocation succeeds. In this case, the + allocation will fail for an indefinite + number of times.

+
+byte* GC::collect_alloc(unsigned size, TLS* tls) {
+
     scan = tospace;
     copy = tospace;
     toend = tospace + semisize;
@@ -1063,22 +1069,34 @@
 
     vm_resume_threads_after();
     return obj;
-}
-
-

The exported GC interface is mostly implemented by delegating the task to the -method of the structure GC. The GC initialization function init() is called -from gc_init().

-
-
-
void gc_init() {
+}
+
+ +

The exported GC interface is mostly + implemented by delegating the task to + the method of the structure + GC. The GC initialization + function init() is called + from gc_init().

+ +
+
+
+void gc_init() {
     gc.init();
-}
-
-

Thread local allocation areas are reset on thread creation and thread -termination events.

-
-
-
void gc_thread_init(void* tp) {
+}
+
+
+
+ +

Thread local allocation areas are + reset on thread creation and thread + termination events.

+ +
+
+
+void gc_thread_init(void* tp) {
     TRACE2("gc.thread", "gc_thread_init " << tp);
     TLS* tls = (TLS*) tp;
     std::list<TLS*>::iterator i =
@@ -1100,13 +1118,17 @@
 
     tls->current = NULL;
     tls->limit = NULL;
-}
-
-

The slow path allocation function gc_alloc() checks whether the allocation space is -exhausted and starts garbage collection when necessary.

-
-
-
Managed_Object_Handle gc_alloc (unsigned size, Allocation_Handle ah, void *tp) {
+}
+
+ +

The slow path allocation + function + gc_alloc() checks + whether the allocation space is + exhausted and starts garbage + collection when necessary.

+
+Managed_Object_Handle gc_alloc (unsigned size, Allocation_Handle ah, void *tp) {
     Managed_Object_Handle obj;
     TLS* tls = (TLS*) tp;
 
@@ -1150,13 +1172,18 @@
     assert(NULL == obj ||
         (gc.fromspace <= obj && obj < gc.limit && ((int)obj & 3) == 0));
     return obj;
-}
-
-

If the memory is exhausted, the no-collection allocation function -gc_alloc_fast() returns NULL, and does not start garbage collection.

-
-
-
Managed_Object_Handle gc_alloc_fast (unsigned size, Allocation_Handle ah, void *tp) {
+}
+
+ +

If the memory is exhausted, + the no-collection allocation + function + gc_alloc_fast() + returns NULL, and + does not start garbage + collection.

+
+Managed_Object_Handle gc_alloc_fast (unsigned size, Allocation_Handle ah, void *tp) {
     Managed_Object_Handle obj;
     TLS* tls = (TLS*) tp;
     size = size & 0x3fffffff;
@@ -1171,24 +1198,31 @@
     assert(NULL == obj ||
         (gc.fromspace <= obj && obj < gc.limit && ((int)obj & 3) == 0));
     return obj;
-}
-
-

The root set enumeration function passes the root reference to the root() -function.

-
-
-
void gc_add_root_set_entry(Managed_Object_Handle *ref, Boolean is_pinned) {
+}
+
+ +

The root set enumeration + function passes the root + reference to the + root() + function.

+
+void gc_add_root_set_entry(Managed_Object_Handle *ref, Boolean is_pinned) {
     assert(!is_pinned);
     TRACE2("gc.root", "gc_add_root_set_entry " << ref << " -> " << *ref);
     if (NULL == *ref) return;
     gc.root(ref);
-}
-
-

The function build_slot_offset_array() is used to construct a NULL-terminated -list of offsets of reference fields.

-
-
-
static int *build_slot_offset_array(Class_Handle ch)
+}
+
+ +

The function + build_slot_offset_array() + is used to construct a + NULL-terminated + list of offsets of reference + fields.

+
+static int *build_slot_offset_array(Class_Handle ch)
 {
     unsigned num_ref_fields = 0;
     // Get the total number of fields including primitive fields.
@@ -1225,13 +1259,15 @@
     *p = 0;
 
     return ref_array;
-}
-
-

The GC caches object layout information when the function gc_class_prepared() -is called.

-
-
-
void gc_class_prepared (Class_Handle ch, VTable_Handle vth) {
+}
+
+ +

The GC caches object layout + information when the function + gc_class_prepared() + is called.

+
+void gc_class_prepared (Class_Handle ch, VTable_Handle vth) {
     TRACE2("gc.prepared", "gc_class_prepared("
             << class_get_name(ch) << ")");
     OI** vt = (OI**) vth;
@@ -1257,45 +1293,77 @@
         oi->offsets = build_slot_offset_array(ch);
         oi->has_slots = (oi->offsets != NULL);
     }
-}
-
-

The function gc_force_gc() starts a forced garbage collection using the global -GC lock to ensure that only one thread is doing a collection at any time. It -passes null arguments to collect_alloc(), because it requires no -allocation.

-
-
-
void gc_force_gc () {
+}
+
+ +

The function + gc_force_gc() + starts a forced garbage + collection using the global GC + lock to ensure that only one + thread is doing a collection at + any time. It passes null + arguments to + collect_alloc(), + because it requires no + allocation.

+
+void gc_force_gc () {
     vm_gc_lock_enum();
     gc.collect_alloc(0, NULL);
     vm_gc_unlock_enum();
-}
-
-

Other functions of the GC interface are empty or trivial, and not described in -this document. You can see the full listing in the gc_copying.cpp file.

-

After you completed coding the garbage collector, you can build a GC dynamic -library, as described above, by typing

-
-
-
build$ build.bat -DCOMPONENTS=vm.gc_copying
-
-
-

4. Running VM with the custom GC

-
-

This section describes how to run the DRL virtual machine with the custom -garbage collector library.

-

You can specify the name of the dynamic library on the command line. For -example, to load a GC gc_copying.dll, execute the following:

-
-
-
ij -Dvm.dlls=gc_copying Hello
-
-

The virtual machine searches for a dynamic library gc_copying.dll in the -default locations, that is, the value for the PATH variable and the location of -executable ij.exe. -The default garbage collector is gc.dll located in the same bin/ directory as ij.exe.

-
- - - +} + + +

Other functions of the GC + interface are empty or trivial, + and not described in this + document. You can see the full + listing in the + gc_copying.cpp + file.

+ +

After you completed coding + the garbage collector, you can + build a GC dynamic library, as + described above, by typing

+
+build$ build.bat -DCOMPONENTS=vm.gc_copying
+
+
+
+ +

+ + 5. Running the VM with the Custom + GC

+ +

This section describes how to run + the DRL virtual machine with the custom + garbage collector library.

+ +

You can specify the name of the + dynamic library on the command line. + For example, to load a GC + gc_copying.dll, execute + the following:

+
+ij -Dvm.dlls=gc_copying Hello
+
+ +

The virtual machine searches for a + dynamic library + gc_copying.dll in the + default locations, that is, the value + for the PATH variable and the location + of executable ij.exe. The + default garbage collector is + gc.dll located in the same + bin/ directory as + ij.exe.

+ + + + + \ No newline at end of file