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.