Overview

Every “storable piece of information” in MuPDF is held in a data structure that begins with a fz_storable structure. Rather than repeatedly say “a storable piece of information”, we shall henceforth just say “a fz_storable”.

MuPDF uses reference counting for most of its data structures (see ReferenceCounting ReferenceCounting), and fz_storables are no exception.

The objects in the Store are held in a chain according to when they were last used. Whenever an object is `used', it is moved to the head of the chain. Whenever we need to evict an object from the Store to make room, we therefore discard objects from the tail of the chain. In this way frequently used objects are kept around, while rarely used ones are discarded in preference.

Whenever MuPDF needs to use a fz_storable, it first checks to see if there is one in the Store already. It does this by forming a unique `key' and scanning the Store for an object of a given type, with that key. If the object exists within the Store, the fact that the object has been used is noted (i.e. it is moved to the front of the usage chain), a reference is taken, and returned to the caller.

If no reference is returned, the code creates its own version of the fz_storable. It calculates its size, and puts it into the Store, together with the same key as before. The Store takes a reference to the object, links it into its data structure, and updates its running total of the size of all the objects within it.

If placing a new object into the Store would take it over the limit, it runs through and looks for the least recently used objects to evict to bring the limit down. In order for an object to be considered for eviction, their refcount must be 1. We know that the Store is holding 1 reference to the object - if anything else is, then removing it from the Store won't actually save us any memory.

Regardless of whether the Store can be reduced to a suitable size, the object is always placed into the store. This ensures that the Store's figure for “amount of memory used by fz_storable's” remains correct (thus ensuring that should objects become evictable, the store size will fall correctly). It also does no harm, because clearly we have managed to allocate enough memory to form the fz_storable in the first place.

Regardless of whether a caller finds the object in the Store, or has to store it itself, it then proceeds identically. It uses the object for whatever purpose it needed it, and then calls the appropriate fz_drop function to lose its reference. The object will live on in the Store until it needs to be evicted to make room.

When the fz_context (or, more accurately, the last of a set of cloned contexts) is finally destroyed, the Store is destroyed too. This results in every object in the Store being released. Unless something has gone wrong with reference counting, this will result in all our objects being freed.