21.3 Reference Counting

As mentioned above, most MuPDF objects are reference counted. This means that on creation (typically with a fz_new_... call), they have a reference count of 1. Think of these object pointers as ‘handles’.

In the event that a fz_new_... call fails (perhaps due to running out of memory), then it will tidy up any partially constructed object(s) before throwing an exception.

If a ‘copy’ of the object is required, a new handle can be generated using the appropriate fz_keep_... call. This is a very low cost operation that just involves incrementing the reference count, so no physical copying of the data is involved. Accordingly it is vital that objects that have multiple handles do not have their contents altered.

Once a reference is finished with, it should be disposed of using the appropriate fz_drop_... call. This is true regardless of whether the handle was created by a fz_new_... or a fz_keep_... call. This drops the reference count by 1.

Once the reference count hits 0, the storage used by the object is freed.

It is a matter of design that no fz_drop_... (or fz_free) call ever throws an exception. Furthermore, all such ‘destructor’ calls must accept a NULL pointer (and do nothing). This vastly simplifies error handling in most cases.

As an implementation detail, certain objects within MuPDF are allocated statically and have a reference count of -1. Any negative values are unaffected by reference counting operations, and will never be freed. Nonetheless, these should be treated exactly as normal objects and kept/dropped as usual.

It is up to the developer to choose which size of storage to use for the reference count, remembering that the MuPDF counting routines do not detect overflow. If someone takes more than 127 references to an object built upon an int8_t, for example, the reference counting routines will believe that it is a static object, and it will never be freed.