Back in the old days, allocation was static - there was a fixed number of terrain textures, for example (600). Memory management was trivial, every resource went in its slot, and the code was really bullet-proof. On the other hand, it didn't scale well (meaning at all).
Parts of the code evolved to use a cache-and-retain system...each resource was loaded once the first time it was needed and retained forever. This was dynamic and good.
Unfortunately as the hardware is capable of blasting out more graphic data, scenery has gotten more complex, and now if we retain everything we tend to run out of virtual memory. So now X-Plane uses a reference-counting system to share resources but purge them when they're not used.
But the code isn't as simple as saying "if the ref count drops to zero, nuke the object". The problem is: consider two scenery files A and B that use three catagories of objects:
1. Objects only in A.
2. Objects only in B.
3. Objects in both A and B.
If we load scenery B before purging A, and we use simple ref counting, we will have all three sets of objects loaded at once. That's bad, because our total virtual memory footprint will temporarily spike up, possibly exhausting supply.
If we purge A and then load B, the objects in catagory 3 are deleted and immediately reloaded. That's unnecessarily slow.
So instead X-Plane uses the following rules:
- Objects are retained when their reference count is zero.
- All objects of reference count zero are explicitly purged via a global call.
- scenery A is purged before B is loaded.
- All new objects are loaded as lazily as possible, during flight.
- Purge scenery A. (Class 1 and 3 objects ref count goes to zero.)
- Load scenery B. (Class 3 objects ref count goes back to 1. Class 2 objects ref count is 1 but they are not yet loaded. So far our memory usage for objects hasn't changed.)
- Purge all unused objects. (Class 1 objects are now nuked. Memory goes down.)
- Start lazily loading missing objects. (Class 2 objects are loaded. Memory goes back up.)