For NVSG, efficient memory management is key to optimizing performance and effectively utilizing available memory.
Frequent memory allocations and deallocations play a significant role in degrading application performance. Because a default memory manager is general purpose, it cannot provide the best performance. Also, chaotic software systems tend to suffer from memory leaks and premature object deletion. Memory leaks eventually slow down an application, and premature object deletion can crash a system in cases where memory is accessed after it was already deleted.
NVSG uses a memory manager that is highly optimized for dealing with NVSG specific data structures, and addresses problems that are common to standard memory managers and more chaotic software systems. For example, NVSG uses reference counting, which results in a less chaotic software system that avoids memory corruption in terms of either memory leaks or premature deletion. (See also How to Enable Memory Leak Detection in Debug Mode.)
This section explains the memory management process used by NVSG, and how it affects the methods used to create and delete NVSG objects.
Principles of NVSG Memory Management
The IAllocator class provides an interface to the memory manager by overloading the new and delete operators. NVSG classes utilize this interface through inheritance. This design provides a standard way of using new and delete to allocate and deallocate objects from memory.
The other essential design for NVSG memory management is reference counting. Reference counting conveniently eliminates the burden of object ownership and is basically a simple form of garbage collection. NVSG objects inherit from RCObject, which provides the base functionality for reference counting - that is, encapsulation of the reference count methods and manipulations.
The NVSG framework uses reference counting to
The life of an NVSG object is as follows:
NVSG objects are subject to certain restrictions with respect to memory management:
new
operator.GeoNode node; // error! NVSG objects can live on heap only! GeoNode *pNode0 = new GeoNode; // error! NVSG objects can't be created using \c new const GeoNode * pNode1= GeoNode::create(); // fine, creating a GeoNode object on heap using the creation function // ... delete pNode1; // error! explicit deletion of NVSG objects is not permitted
As a consequence, one cannot store NVSG objects in STL containers like vector or map. Of course, pointers to NVSG objects can be stored in STL containers.
After creating an NVSG object, the reference count of that object is 0. In other words, the object has been allocated and constructed but not yet referenced. To properly reference the object, one must call addRef
on that object.
const GeoNode * pNode = GeoNode::create(); // allocate and construct a GeoNode object // reference count is 0! pNode->addRef(); // reference the newly created object // reference count is 1!
The reason that the reference count of an NVSG object is 0 after allocation and construction is that, in many cases, code that allocates and constructs the object does not really reference it, but instead passes it to subsequent layers. In that situation, it would result in unnecessary overhead to also manage the object's life time. For example, a loader might construct a GeoNode object and pass it to a Transform object. In this case the Transform code would be the code which actually references the GeoNode object.
const Transform * pTrafo = Transform::create(); pTrafo->addRef(); const GeoNode * pNode = GeoNode::create(); // create a GeoNode object Transform * pNC = beginEdit( pTrafo ); pNC->addChild(pNode); // pass the GeoNode object to the Transform endEdit( pNC ); // ... no need to care about the GeoNode's lifetime
A NVSG object is destroyed and deallocated from memory after its reference count reaches 0 - that is, when nobody is using it any longer. For proper tracking of an object's ownership, code that no longer references an object should call removeRef
on that object.
const GeoNode * pNode = GeoNode::create(); // allocate and construct a GeoNode object // reference count is 0! pNode->addRef(); // reference the newly created object // reference count is 1! pNode->removeRef(); // unreference the object // reference count reaches 0, // and hence the object is destroyed and deallocated from memory
Back to