2005/5/10

     
 

ACDK Heaps

artefaktur

| Heaps | Allocator | Memory Debuging | RC/GC mechanism |



ACDK contains a flexible Memory Management Framework


Content of this chapter:

   Stack / HeapObjects
   Allocation framework
     Criteria
   Selecting Heap
   Available Heaps
     PA_Heap
       Reference Counting
       Mark/Sweep Garbage Collecting
       Limit usage of memory
       Iterates all heap objects
       Additionally features
     RC_Heap
     RC_GC_Heap
     GC_Heap
       Install the Boehm Garbage Collector
       Usage



 Stack / HeapObjects

Stack object are fast, easy to manage, thread and exception safe.
But for complex frameworks the often doesn't fit very well, references or Pointer are more flexible (remind: Most problems in programming can be solved through an additional indirection).

ACDK supports both: Allocation objects on the stack and on the heap.

For allocating objects on the heap, please refer to  Stack.

 Allocation framework

ACDK support an allocation framework with some predefined Heaps and assoicated  Allocators.

 Criteria

  • Allocators which supports Garbage Collection with cyclic references.
  • Allocators which supports enumeration of objects.
  • Performance of Allocators.
  • Fixed size Allocators.
  • Reference Counted Allocators or Introspection (Mark/Sweep) Garbage collectors.
  • Threadsafe Allocators.
  • Allocators for better scalibity in multiple threads.
  • Allocators with sanity check agains out of bounds writing.

 Selecting Heap

The Heap, ACDK should use at default can be specified via a command line option.
Please refer to  man acdk_core.

 Available Heaps


 PA_Heap

PageAllocator Heap is the default Heap for ACDK.

PageAllocator Heap supports:

 Reference Counting

Standard reference counting will be used to keep memory footprint small.

 Mark/Sweep Garbage Collecting

On low memory situation the Heap automatically starts the Mark/Sweek Garbage Collecting to free objects with cyclic reference, which could not be freed by reference counting.



 Limit usage of memory

With the PageAllocator Heap the memory usage of a thread or globally of all threads can be limited.
The value for the maximum usage of memory can be given by the command line option -acdk-maxmem [maxmem] (see also  man acdk_core) or via the  acdk::lang::System.

If the limit is reached, the PageAllocator starts Mark/Sweep Garbage Collecting.
If still not enough memory is available, a OutOfMemoryException will be thrown.

Sample for limit memory usage, and automatic garbage collecting

  jlong mmu = System::getMaxMemoryUsage();
  jlong cmu = ObjectHeap::curMemUsage();
  
  System::setMaxMemoryUsage(cmu + 1024 * 1024 * 2);
  for (int i = 0; i < 1000; ++i)
  {
    // in the background automatically Mark/Sweek GC will be called
    RGcableObject lobj = new GcableObject(); 
    lobj->_other = lobj; // cyclic reference, reference counting gc will not work
  }
  System::setMaxMemoryUsage(mmu);
  System::gc(); // clean garbage

Sample for handling out of memory situation

  jlong mmu = System::getMaxMemoryUsage();
  jlong cmu = ObjectHeap::curMemUsage();
  
  System::setMaxMemoryUsage(cmu + 1024 * 1024 * 2);
  try {
    RObjectArray holder = new ObjectArray(0);
    // run until out of mem
    while (true)
    {
      holder->append(new String("Just a Text"));
    }
  } catch (ROutOfMemoryException ex) {
  }
  
  System::setMaxMemoryUsage(mmu);

 Iterates all heap objects

Following source demonstrates how listing all root objects work:

  RInteger rint1 = new Integer(12345678); // is root object
  RInteger rint2 = new Integer(8765432);
  RObjectArray n = new ObjectArray(1);
  n[0] = &rint2; // rint2 is not root, because member of n
  
  // get all root objects
  RObjectArray roots = System::getRootObjects();
  testAssert(roots->find(&rint1) != -1);
  testAssert(roots->find(&rint2) == -1);
  for (int i = 0; i < roots->length(); ++i)
  {
    RObject o = roots[i];
    if (instanceof(o, ObjectArray) == true)
    {
      RObjectArray oa = (RObjectArray)o;
      ::acdk::lang::System::out->println(
        SBSTR("Root Object: (" << Integer::toHexString((int)(void*)o.impl()) << "): " 
              << o->getClass()->getName() << ": " << oa->length()));
      for (int i = 0; i < oa->length(); ++i)
      {
        o = oa[i];
        if (o != Nil)
          ::acdk::lang::System::out->println(
            SBSTR("  RootArray Object: (" << Integer::toHexString((int)(void*)o.impl()) << "): " 
              << o->getClass()->getName() << ": " << o->toString()));
      }
    }
    else
    {
      ::acdk::lang::System::out->println(
        SBSTR("Root Object: (" << Integer::toHexString((int)(void*)o.impl()) << "): " 
          << o->getClass()->getName() << ": " << o->toString()));
    }
  }


 Additionally features

If an memory object will be freed in the PageAllocator Heap, the heap checks if somebody wrote outside the bounds of the memory object.

 RC_Heap

A simple Reference Counting Heap.
It doesn't support Mark/Sweep garbage collecting for cyclic objects.
The memory will be allocated directly from the underlying C/C++ heap.

 RC_GC_Heap

A Heap based on Reference Counting + Garbage Collecting for cyclic references.
The memory will be allocated directly from the underlying C/C++ heap.
The bookkeeping will of all allocated memory chunks will be done container.


 GC_Heap

Garbage Collecting Heap using the Boehm Garbage Collector.

 Install the Boehm Garbage Collector

Unfortunatelly the Boehm GC doens't work with ACDK in a stable way.
I will spend for this a little more time.

To integrate the Boehm Garbage Collector you have to do following steps:
  • Download the Boehm Garbage Collector 6.0 or later.
  • add the library gc.lib to all ACDK libraries and executable.
  • add gc6.0/include path to your Include Path.
  • Add the defines to ACDK_HAS_BOEHMGC and ACDK_NO_REFCOUNTING to your ACDK projects. Alternativally you can edit the ./acdk/Config.h file and add these defines.
  • Copy the gc.dll/gc.so to the ACDKHOME/bin directory.

 Usage

Other changes in the ACDK sources are not necessary. But there are some limitations:
  • The BGC will not work with other Heaps, because for performance reasons the Reference Counting will be deactivated when using the BGC.
  • Some special Debugging features inspecting the allocated Objects will not work.
  • The WeakReference/WeakHashmap will not work.
  • Currently no destructor will work.