Each object stored in a persistent memory pool is represented by an object handle of type PMEMoid. In
practice, such a handle is a unique Object IDentifier (OID) of global scope, which means that two objects
from different pools will never have the same OID. The special OID_NULL macro defines a NULL-like handle
that does not represent any object. The size of a single object is limited by PMEMOBJ_MAX_ALLOC_SIZE.
Thus an allocation with a requested size greater than this value will fail.
An OID cannot be used as a direct pointer to an object. Each time the program attempts to read or write
object data, it must obtain the current memory address of the object by converting its OID into a point‐
er.
In contrast to the memory address, the OID value for given object does not change during the life of an
object (except for realloc), and remains valid after closing and reopening the pool. For this reason, if
an object contains a reference to another persistent object, for example, to build some kind of a linked
data structure, the reference must be an OID and not a memory address.
pmemobj_direct() returns a pointer to the PMEMoid object with handle oid.
pmemobj_oid() returns a PMEMoid handle to the object pointed to by addr.
pmemobj_type_num() returns the type number of the PMEMoid object with handle oid.
pmemobj_pool_by_oid() returns a PMEMobjpool* handle to the pool containing the PMEMoid object with handle
oid.
pmemobj_pool_by_ptr() returns a PMEMobjpool* handle to the pool containing the address addr.
At the time of allocation (or reallocation), each object may be assigned a number representing its type.
Such a typenumber may be used to arrange the persistent objects based on their actual user-defined
structure type, thus facilitating implementation of a simple run-time type safety mechanism. This also
allows iterating through all the objects of a given type that are stored in the persistent memory pool.
See pmemobj_first(3) for more information.
The OID_IS_NULL() macro checks if PMEMoid represents a NULL object.
The OID_EQUALS() macro compares two PMEMoid objects.
For special cases where volatile (transient) variables need to be stored on persistent memory, there’s a
mechanism composed of structpmemvlt type and pmemobj_volatile() function. To use it, the structpmemvlt
needs to be placed in the neighborhood of transient data region. The PMEMvlt macro can be used to con‐
struct such a region. The structpmemvlt must be zeroed prior to use. This can be easily done in object
constructor or in a transaction directly after an allocation. When the pmemobj_volatile() function is
called on a structpmemvlt, it will return the pointer to the data and it will ensure that the provided
constructor function is called exactly once in the current instance of the pmemobj pool. The constructor
is called with the ptr pointer to the data, and this function will return the same pointer if the con‐
structor returns 0, otherwise NULL is returned. The size argument must accurately describe the total
size of the volatile memory region that will be accessed. Calling pmemobj_volatile() on the same region
with different sizes is undefined behavior. For this mechanism to be effective, all accesses to tran‐
sient variables must go through it, otherwise there’s a risk of the constructor not being called on the
first load. Maintaining transient state on persistent memory is challenging due to difficulties with dy‐
namic resources acquisition and subsequent resource release. For example, one needs to consider what
happens with volatile state of an object which is being freed inside of a transaction, especially with
regards to the possibility of an abort. It’s generally recommended to entirely separate the persistent
and transient states, and when it’s not possible, to only store types which do not require lifecycle man‐
agement (i.e., primitive types) inside of volatile regions.