The lifecycle of RuntimeProfile objects and counters is confusing and error-prone. In particular, there are various undocumented requirements about the order destructors are run in.
Some RuntimeProfile counters are registered to be periodically updated by a thread. This thread touches the counter object, and in some cases other objects (e.g. MemTrackers). References to RuntimeProfile counters are also stored in various places. There are a couple of specific problems I'm aware of:
- ~RuntimeProfile deregisters counters from being updated by a background thread. It must be run before those counters are destroyed. This currently works because either the RuntimeProfile lives in the same ObjectPool as the counters and ObjectPools destroy objects in FIFO order, or because the RuntimeProfile is destroyed before the ObjectPool.
- MemTracker destructors reference the consumption() counter, so the MemTracker must be destroyed before the counter. In practice this means that a MemTracker cannot always be managed by an ObjectPool because destructors will be run in the wrong order (unless it is using MemTracker::local_counter_).