vm$ mkdir gc_copying -vm$ mkdir gc_copying/src -vm$ cd gc_copying/src-
Index: gc-howto-content.html =================================================================== --- gc-howto-content.html (revision 454321) +++ gc-howto-content.html (working copy) @@ -1,359 +1,139 @@ - - -
- - - -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:
-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.
-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.
-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.
-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.
-#include "open/gc.h" +</project> ++ +
You can add other macro definitions, + include directories or + compiler-specific command-line options + to match your needs.
+ +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.
-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!
-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.
-These include files are located in
+ directories
+ vm/include/open and
+ vm/port/include. Consult
+ their content for documentation and
+ details of the interface.
Run the build system to test whether + the infrastructure is set up + correctly:
++build$ build.bat -DCOMPONENTS=vm.gc_copying +-gc_wrapup() shuts down the GC +
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.
Note
-gc_vm_initialized() notifies the GC about the VM transition from the - initialization stage to running user applications +This empty library + will not work, you have to write your + GC first.
+ + +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.
gc_init()
+ initializes the garbage
+ collectorgc_wrapup() shuts
+ down the GCgc_vm_initialized()
+ notifies the GC about the VM
+ transition from the initialization
+ stage to running user
+ applicationsgc_thread_init()
+ and gc_thread_kill()
+ notify the GC about creation and
+ termination of user threads that
+ may request memory allocation or
+ other GC servicesgc_class_prepared()
+ notifies the GC about loaded and
+ prepared classesgc_alloc()
+ performs slow allocation, can
+ trigger garbage collectiongc_alloc_fast()
+ performs faster allocation, should
+ not trigger garbage collectiongc_add_root_set_entry()
+ is responsible for enumerationgc_add_root_set_entry()
+ enumerates one root pointerSee the + + Root Set Enumeration section in the + Developer's + Guide for details.
+ +gc_supports_compressed_references()
+ indicates whether GC supports
+ compressed referencesSee the Root set enumeration section in the Developer's Guide for details.
-gc_is_object_pinned()
+ indicates whether the GC will move
+ an object or notgc_force_gc()
+ forces a garbage collectionThe virtual machine can operate + without the functions listed below, but + certain features will be + unavailable.
-gc_is_object_pinned() indicates whether the GC will move an object or not +gc_free_memory()
+ returns the estimated amount of
+ memory available for
+ allocationgc_pin_object()
+ requests that the GC does not move
+ an objectgc_unpin_object()
+ removes the restriction on not
+ moving an objectThe virtual machine can operate without the functions listed below, but certain features -will be unavailable.
-gc_get_next_live_object()
+ iterates over live objects during
+ the stop-the-world phase of garbage
+ collectiongc_finalize_on_exit()
+ transfers finalizable queue
+ contents to the VM core on
+ shutdowngc_time_since_last_gc()
+ returns the amount of time that
+ elapsed since the previous
+ collection, in millisecondsgc_total_memory()
+ returns the overall amount of
+ memory used for the Java heapgc_max_memory()
+ returns the maximum amount of
+ memory that can be used for the
+ Java heapVM_GC
+ InterfaceThe 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 + Developer's + Guide.
-gc_finalize_on_exit() transfers finalizable queue contents to the VM core on - shutdown +DRLVM provides two functions to + support thread suspension and root set + enumeration simultaneously:
-vm_enumerate_root_set_all_threads()
+ suspends all user threads and
+ initiates root set enumerationvm_resume_threads_after()
+ resumes execution of user
+ threadsThese functions effectively restrict + the garbage collector to stop-the-world + algorithms only.
+ +This section gives step-by-step + instructions on how to implement the + garbage collection algorithm. The + example shows a semispace copying + collector.
-Note
-gc_max_memory() returns the maximum amount of memory that can be used for the - Java heap +This example does + not implement object finalization and + weak references.
+ +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:
-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.
-vm_enumerate_root_set_all_threads() suspends all user threads and initiates - root set enumeration +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.
-vm_resume_threads_after() resumes execution of user threads +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.
-These functions effectively restrict the garbage collector to stop-the-world algorithms only.
-This section gives step-by-step instructions on how to implement the garbage -collection algorithm. The example shows a semispace copying collector.
-This example does not implement object finalization and weak references.
-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.
-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;
-};
-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.
-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-
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 ++
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.