About
Side Projects
Blog
2019-05-25

Memory Management Helpers in Haiku

Keeping track of heap-allocated data in a software environment without garbage-collection is a challenge to do well and development environments typically provide some support to help make a good outcome possible.

OPENSTEP

When I worked on software for the NeXT and later MacOS/iOS environments I became familiar with OPENSTEP’s approaches around -retain, -release and -autorelease in the Objective-C language. In this mechanic, the current thread would typically have one or more “autorelease-pool” objects on the stack. Any object O that was sent an -autorelease message would be assigned to the nearest autorelease-pool up the stack and O would be deallocated as soon as the associated autorelease-pool object was deallocated. Alternatively an object could be manually managed; the retain count of an object could be incremented with a -retain method invocation and decremented with -release. When the retain count hits 0, the object is deallocated. This works well although most people working with iOS and MacOS today are using a form of garbage collection.

BReferenceable

More recently while undertaking hobby-computing on the Haiku platform I have encountered the BReferenceable reference-counting approach. This system is aimed at use with C++ heap-resident object instances; those that are allocated with new. Objects that should be reference-counted subclass from BReferenceable and in the BReferenceable implementation one finds the equivalent of the -retain as AcquireReference() and the equivalent of -release as ReleaseReference(). Again, when the reference count drops to zero, the object is deleted.

The templated BReference<T> object provides a clever way to deal with reference-counting in Haiku applications. Instances of BReference<T> are created holding a pointer to an object. You might use a BReference<T> as an member variable of another class. Here is an example;

class Language : public BReferenceable { ... }

class Comment
{
...
private:
   BReference<Language> fLanguage;
}

Language* language = new Language("en", "English");
...
Comment* comment1 = new Comment(BReference<Language>(language, true));
Comment* comment2 = new Comment(BReference<Language>(language));
...
delete comment1;
delete comment2;

Consider the retain count of language in the pseudo-code above;

Action language Retain-count
1 language is created 1
2 comment1 is created and the BReference contructor uses true for the second argument as to not increment the reference count. 1
3 comment2 is created 2
4 comment1 is deleted 1
5 comment2 is deleted 0

Because the retain count of language is finally at 0, it is deleted.

The macro behaviour is that the number of instances of a BReference existing for a given BReferenceable object determines its reference count. Once the last BReference goes, the BReferenceable object goes too.

You can see this mechanism at work in the HaikuDepot project. See the LanguageModel class where the fSupportedLanguages has the LanguageRef (BReference<Language>) objects added into it; each of which is a BReference to a Language instance. Once the reference is removed from the list, the corresponding Language object is deallocated.

Conveniently it is possible to make a method call on the object held by a BReference<T> by using the -> operator like this;

Language* language = new Language("en", "English");
BReference<Language> languageRef = BReference(language, true);
languageRef->Code();

ObjectDeleter

There is no direct equivalent to the “autorelease-pool” of OPENSTEP, but something a little bit similar within a single stack frame is the ObjectDeleter. The ObjectDeleter is not related to the BReferenceable mechanism. An ObjectDeleter can be attached to an object instance to delete it when the ‘deleter’ falls out of scope. Here is an example;

#include <AutoDeleter.h>
...
status_t
ServerPkgDataUpdateProcess::ProcessLocalData()
{
  PackageFillingPkgListener* itemListener =
    new PackageFillingPkgListener(...);
  ObjectDeleter<PackageFillingPkgListener>
    itemListenerDeleter(itemListener);
  ...
}

When the method scope ends, the itemListenerDeleter is deleted and hence the itemListener is deleted as well without having to explicitly delete the itemListener in the code-logic flow.

Summary

These behaviours are useful and help in managing object memory within Haiku software more safely. The APIs and documentation for these classes can be found in the Haiku Book class list.