diff --git a/indra/llcommon/lleventtimer.cpp b/indra/llcommon/lleventtimer.cpp
index 0d96e03da41ba1d07ff5f0aae9e85ed33b7a8581..3986dee3acbd52909dce42b23c418523efa2db02 100644
--- a/indra/llcommon/lleventtimer.cpp
+++ b/indra/llcommon/lleventtimer.cpp
@@ -58,9 +58,8 @@ LLEventTimer::~LLEventTimer()
 void LLEventTimer::updateClass() 
 {
 	std::list<LLEventTimer*> completed_timers;
-	for (instance_iter iter = beginInstances(); iter != endInstances(); ) 
+	for (auto& timer : instance_snapshot())
 	{
-		LLEventTimer& timer = *iter++;
 		F32 et = timer.mEventTimer.getElapsedTimeF32();
 		if (timer.mEventTimer.getStarted() && et > timer.mPeriod) {
 			timer.mEventTimer.reset();
diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp
index 3d28cd15b02234f3c28756d53f570bc21ea07ba2..08ea668964eec0e1fb18e1e8f22405dd37c7f429 100644
--- a/indra/llcommon/llfasttimer.cpp
+++ b/indra/llcommon/llfasttimer.cpp
@@ -193,27 +193,26 @@ TimeBlockTreeNode& BlockTimerStatHandle::getTreeNode() const
 
 void BlockTimer::bootstrapTimerTree()
 {
-	for (BlockTimerStatHandle::instance_tracker_t::instance_iter it = BlockTimerStatHandle::instance_tracker_t::beginInstances(), end_it = BlockTimerStatHandle::instance_tracker_t::endInstances(); 
-		it != end_it; 
-		++it)
+	for (auto& base : BlockTimerStatHandle::instance_snapshot())
 	{
-		BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(*it);
+		// because of indirect derivation from LLInstanceTracker, have to downcast
+		BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(base);
 		if (&timer == &BlockTimer::getRootTimeBlock()) continue;
 
 		// bootstrap tree construction by attaching to last timer to be on stack
 		// when this timer was called
 		if (timer.getParent() == &BlockTimer::getRootTimeBlock())
-{
+		{
 			TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator();
 
 			if (accumulator.mLastCaller)
-	{
+			{
 				timer.setParent(accumulator.mLastCaller);
 				accumulator.mParent = accumulator.mLastCaller;
-		}
+			}
 			// no need to push up tree on first use, flag can be set spuriously
 			accumulator.mMoveUpTree = false;
-	}
+		}
 	}
 }
 
@@ -306,12 +305,10 @@ void BlockTimer::processTimes()
 	updateTimes();
 
 	// reset for next frame
-	for (BlockTimerStatHandle::instance_tracker_t::instance_iter it = BlockTimerStatHandle::instance_tracker_t::beginInstances(),
-			end_it = BlockTimerStatHandle::instance_tracker_t::endInstances();
-		it != end_it;
-		++it)
+	for (auto& base : BlockTimerStatHandle::instance_snapshot())
 	{
-		BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(*it);
+		// because of indirect derivation from LLInstanceTracker, have to downcast
+		BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(base);
 		TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator();
 
 		accumulator.mLastCaller = NULL;
@@ -362,12 +359,10 @@ void BlockTimer::logStats()
 		LLSD sd;
 
 		{
-			for (BlockTimerStatHandle::instance_tracker_t::instance_iter it = BlockTimerStatHandle::instance_tracker_t::beginInstances(), 
-				end_it = BlockTimerStatHandle::instance_tracker_t::endInstances(); 
-				it != end_it; 
-			++it)
+			for (auto& base : BlockTimerStatHandle::instance_snapshot())
 			{
-				BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(*it);
+				// because of indirect derivation from LLInstanceTracker, have to downcast
+				BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(base);
 				LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording();
 				sd[timer.getName()]["Time"] = (LLSD::Real) (frame_recording.getLastRecording().getSum(timer).value());	
 				sd[timer.getName()]["Calls"] = (LLSD::Integer) (frame_recording.getLastRecording().getSum(timer.callCount()));
diff --git a/indra/llcommon/llinstancetracker.cpp b/indra/llcommon/llinstancetracker.cpp
index 3f990f4869c3a504bb9a9c7d656d64a90e5c8279..accb4286e89002d35a9332b1715d14ba2685df84 100644
--- a/indra/llcommon/llinstancetracker.cpp
+++ b/indra/llcommon/llinstancetracker.cpp
@@ -34,18 +34,5 @@
 // external library headers
 // other Linden headers
 
-void LLInstanceTrackerBase::StaticBase::incrementDepth()
-{
-	++sIterationNestDepth;
-}
-
-void LLInstanceTrackerBase::StaticBase::decrementDepth()
-{
-	llassert(sIterationNestDepth);
-	--sIterationNestDepth;
-}
-
-U32 LLInstanceTrackerBase::StaticBase::getDepth()
-{
-	return sIterationNestDepth;
-}
+// This .cpp file is required by our CMake test macro. It contributes no code
+// to the viewer.
diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h
index 363d0bcbd58ce3eeb7ec096e98396863744e232b..76b201ad8cdfe2d4da3b8c75a159068fdd6fefcf 100644
--- a/indra/llcommon/llinstancetracker.h
+++ b/indra/llcommon/llinstancetracker.h
@@ -28,354 +28,456 @@
 #ifndef LL_LLINSTANCETRACKER_H
 #define LL_LLINSTANCETRACKER_H
 
-#include <atomic>
 #include <map>
+#include <set>
+#include <vector>
 #include <typeinfo>
+#include <mutex>
+#include <memory>
+#include <type_traits>
 
-#include "llstringtable.h"
 #include <boost/iterator/transform_iterator.hpp>
 #include <boost/iterator/indirect_iterator.hpp>
+#include <boost/iterator/filter_iterator.hpp>
 
-// As of 2017-05-06, as far as nat knows, only clang supports __has_feature().
-// Unfortunately VS2013's preprocessor shortcut logic doesn't prevent it from
-// producing (fatal) warnings for defined(__clang__) && __has_feature(...).
-// Have to work around that.
-#if ! defined(__clang__)
-#define __has_feature(x) 0
-#endif // __clang__
-
-#if defined(LL_TEST_llinstancetracker) && __has_feature(cxx_noexcept)
-// ~LLInstanceTracker() performs llassert_always() validation. That's fine in
-// production code, since the llassert_always() is implemented as an LL_ERRS
-// message, which will crash-with-message. In our integration test executable,
-// though, this llassert_always() throws an exception instead so we can test
-// error conditions and continue running the test. However -- as of C++11,
-// destructors are implicitly noexcept(true). Unless we mark
-// ~LLInstanceTracker() noexcept(false), the test executable crashes even on
-// the ATTEMPT to throw.
-#define LLINSTANCETRACKER_DTOR_NOEXCEPT noexcept(false)
-#else
-// If we're building for production, or in fact building *any other* test, or
-// we're using a compiler that doesn't support __has_feature(), or we're not
-// compiling with a C++ version that supports noexcept -- don't specify it.
-#define LLINSTANCETRACKER_DTOR_NOEXCEPT
-#endif
-
+/*****************************************************************************
+*   LLInstanceTrackerBase
+*****************************************************************************/
 /**
  * Base class manages "class-static" data that must actually have singleton
  * semantics: one instance per process, rather than one instance per module as
  * sometimes happens with data simply declared static.
  */
+namespace LLInstanceTrackerStuff
+{
+    struct StaticBase
+    {
+        // We need to be able to lock static data while manipulating it.
+        typedef std::mutex mutex_t;
+        mutex_t mMutex;
+    };
+} // namespace LLInstanceTrackerStuff
+
+template <class Static>
 class LL_COMMON_API LLInstanceTrackerBase
 {
 protected:
-    /// It's not essential to derive your STATICDATA (for use with
-    /// getStatic()) from StaticBase; it's just that both known
-    /// implementations do.
-    struct StaticBase
+    typedef Static StaticData;
+
+    // Instantiate this class to obtain a pointer to the canonical static
+    // instance of class Static while holding a lock on that instance. Use of
+    // Static::mMutex presumes either that Static is derived from StaticBase,
+    // or that Static declares some other suitable mMutex.
+    class LockStatic
     {
-        StaticBase():
-            sIterationNestDepth(0)
+        typedef std::unique_lock<decltype(Static::mMutex)> lock_t;
+    public:
+        LockStatic():
+            mData(getStatic()),
+            mLock(mData->mMutex)
         {}
-
-		void incrementDepth();
-		void decrementDepth();
-		U32 getDepth();
-	private:
-#ifdef LL_WINDOWS
-		std::atomic_uint32_t sIterationNestDepth;
-#else
-		std::atomic_uint sIterationNestDepth;
-#endif
-	};
+        Static* get() const { return mData; }
+        operator Static*() const { return get(); }
+        Static* operator->() const { return get(); }
+        // sometimes we must explicitly unlock...
+        void unlock()
+        {
+            // but once we do, access is no longer permitted
+            mData = nullptr;
+            mLock.unlock();
+        }
+    protected:
+        Static* mData;
+        lock_t mLock;
+    private:
+        Static* getStatic()
+        {
+            static Static sData;
+            return &sData;
+        }
+    };
 };
 
-LL_COMMON_API void assert_main_thread();
-
+/*****************************************************************************
+*   LLInstanceTracker with key
+*****************************************************************************/
 enum EInstanceTrackerAllowKeyCollisions
 {
-	LLInstanceTrackerErrorOnCollision,
-	LLInstanceTrackerReplaceOnCollision
+    LLInstanceTrackerErrorOnCollision,
+    LLInstanceTrackerReplaceOnCollision
 };
 
+namespace LLInstanceTrackerStuff
+{
+    template <typename KEY, typename VALUE>
+    struct StaticMap: public StaticBase
+    {
+        typedef std::map<KEY, VALUE> InstanceMap;
+        InstanceMap mMap;
+    };
+} // LLInstanceTrackerStuff
+
 /// This mix-in class adds support for tracking all instances of the specified class parameter T
 /// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup
 /// If KEY is not provided, then instances are stored in a simple set
 /// @NOTE: see explicit specialization below for default KEY==void case
-/// @NOTE: this class is not thread-safe unless used as read-only
-template<typename T, typename KEY = void, EInstanceTrackerAllowKeyCollisions KEY_COLLISION_BEHAVIOR = LLInstanceTrackerErrorOnCollision>
-class LLInstanceTracker : public LLInstanceTrackerBase
+template<typename T, typename KEY = void,
+         EInstanceTrackerAllowKeyCollisions KEY_COLLISION_BEHAVIOR = LLInstanceTrackerErrorOnCollision>
+class LLInstanceTracker :
+    public LLInstanceTrackerBase<LLInstanceTrackerStuff::StaticMap<KEY, std::shared_ptr<T>>>
 {
-	typedef LLInstanceTracker<T, KEY> self_t;
-	typedef typename std::multimap<KEY, T*> InstanceMap;
-	struct StaticData: public StaticBase
-	{
-		InstanceMap sMap;
-	};
-	static StaticData& getStatic() { static StaticData sData; return sData;}
-	static InstanceMap& getMap_() { return getStatic().sMap; }
+    typedef LLInstanceTrackerBase<LLInstanceTrackerStuff::StaticMap<KEY, std::shared_ptr<T>>> super;
+    using typename super::StaticData;
+    using typename super::LockStatic;
+    typedef typename StaticData::InstanceMap InstanceMap;
 
 public:
-	class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
-	{
-	public:
-		typedef boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag> super_t;
-		
-		instance_iter(const typename InstanceMap::iterator& it)
-		:	mIterator(it)
-		{
-			getStatic().incrementDepth();
-		}
-
-		~instance_iter()
-		{
-			getStatic().decrementDepth();
-		}
-
-
-	private:
-		friend class boost::iterator_core_access;
-
-		void increment() { mIterator++; }
-		bool equal(instance_iter const& other) const
-		{
-			return mIterator == other.mIterator;
-		}
-
-		T& dereference() const
-		{
-			return *(mIterator->second);
-		}
-
-		typename InstanceMap::iterator mIterator;
-	};
-
-	class key_iter : public boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag>
-	{
-	public:
-		typedef boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag> super_t;
-
-		key_iter(typename InstanceMap::iterator it)
-		:	mIterator(it)
-		{
-			getStatic().incrementDepth();
-		}
-
-		key_iter(const key_iter& other)
-		:	mIterator(other.mIterator)
-		{
-			getStatic().incrementDepth();
-		}
-
-		~key_iter()
-		{
-			getStatic().decrementDepth();
-		}
-
-
-	private:
-		friend class boost::iterator_core_access;
-
-		void increment() { mIterator++; }
-		bool equal(key_iter const& other) const
-		{
-			return mIterator == other.mIterator;
-		}
-
-		KEY& dereference() const
-		{
-			return const_cast<KEY&>(mIterator->first);
-		}
-
-		typename InstanceMap::iterator mIterator;
-	};
-
-	static T* getInstance(const KEY& k)
-	{
-		const InstanceMap& map(getMap_());
-		typename InstanceMap::const_iterator found = map.find(k);
-		return (found == map.end()) ? NULL : found->second;
-	}
-
-	static instance_iter beginInstances() 
-	{	
-		return instance_iter(getMap_().begin()); 
-	}
-
-	static instance_iter endInstances() 
-	{
-		return instance_iter(getMap_().end());
-	}
-
-	static S32 instanceCount() 
-	{ 
-		return getMap_().size(); 
-	}
-
-	static key_iter beginKeys()
-	{
-		return key_iter(getMap_().begin());
-	}
-	static key_iter endKeys()
-	{
-		return key_iter(getMap_().end());
-	}
+    // snapshot of std::pair<const KEY, std::shared_ptr<T>> pairs
+    class snapshot
+    {
+        // It's very important that what we store in this snapshot are
+        // weak_ptrs, NOT shared_ptrs. That's how we discover whether any
+        // instance has been deleted during the lifespan of a snapshot.
+        typedef std::vector<std::pair<const KEY, std::weak_ptr<T>>> VectorType;
+        // Dereferencing our iterator produces a std::shared_ptr for each
+        // instance that still exists. Since we store weak_ptrs, that involves
+        // two chained transformations:
+        // - a transform_iterator to lock the weak_ptr and return a shared_ptr
+        // - a filter_iterator to skip any shared_ptr that has become invalid.
+        // It is very important that we filter lazily, that is, during
+        // traversal. Any one of our stored weak_ptrs might expire during
+        // traversal.
+        typedef std::pair<const KEY, std::shared_ptr<T>> strong_pair;
+        // Note for future reference: nat has not yet had any luck (up to
+        // Boost 1.67) trying to use boost::transform_iterator with a hand-
+        // coded functor, only with actual functions. In my experience, an
+        // internal boost::result_of() operation fails, even with an explicit
+        // result_type typedef. But this works.
+        static strong_pair strengthen(typename VectorType::value_type& pair)
+        {
+            return { pair.first, pair.second.lock() };
+        }
+        static bool dead_skipper(const strong_pair& pair)
+        {
+            return bool(pair.second);
+        }
+
+    public:
+        snapshot():
+            // populate our vector with a snapshot of (locked!) InstanceMap
+            // note, this assigns pair<KEY, shared_ptr> to pair<KEY, weak_ptr>
+            mData(mLock->mMap.begin(), mLock->mMap.end())
+        {
+            // release the lock once we've populated mData
+            mLock.unlock();
+        }
+
+        // You can't make a transform_iterator (or anything else) that
+        // literally stores a C++ function (decltype(strengthen)) -- but you
+        // can make a transform_iterator based on a _function pointer._
+        typedef boost::transform_iterator<decltype(strengthen)*,
+                                          typename VectorType::iterator> strong_iterator;
+        typedef boost::filter_iterator<decltype(dead_skipper)*, strong_iterator> iterator;
+
+        iterator begin() { return make_iterator(mData.begin()); }
+        iterator end()   { return make_iterator(mData.end()); }
+
+    private:
+        iterator make_iterator(typename VectorType::iterator iter)
+        {
+            // transform_iterator only needs the base iterator and the transform.
+            // filter_iterator wants the predicate and both ends of the range.
+            return iterator(dead_skipper,
+                            strong_iterator(iter, strengthen),
+                            strong_iterator(mData.end(), strengthen));
+        }
+
+        LockStatic mLock;           // lock static data during construction
+        VectorType mData;
+    };
+
+    // iterate over this for references to each instance
+    class instance_snapshot: public snapshot
+    {
+    private:
+        static T& instance_getter(typename snapshot::iterator::reference pair)
+        {
+            return *pair.second;
+        }
+    public:
+        typedef boost::transform_iterator<decltype(instance_getter)*,
+                                          typename snapshot::iterator> iterator;
+        iterator begin() { return iterator(snapshot::begin(), instance_getter); }
+        iterator end()   { return iterator(snapshot::end(),   instance_getter); }
+
+        void deleteAll()
+        {
+            for (auto it(snapshot::begin()), end(snapshot::end()); it != end; ++it)
+            {
+                delete it->second.get();
+            }
+        }
+    };                   
+
+    // iterate over this for each key
+    class key_snapshot: public snapshot
+    {
+    private:
+        static KEY key_getter(typename snapshot::iterator::reference pair)
+        {
+            return pair.first;
+        }
+    public:
+        typedef boost::transform_iterator<decltype(key_getter)*,
+                                          typename snapshot::iterator> iterator;
+        iterator begin() { return iterator(snapshot::begin(), key_getter); }
+        iterator end()   { return iterator(snapshot::end(),   key_getter); }
+    };
+
+    static T* getInstance(const KEY& k)
+    {
+        LockStatic lock;
+        const InstanceMap& map(lock->mMap);
+        typename InstanceMap::const_iterator found = map.find(k);
+        return (found == map.end()) ? NULL : found->second.get();
+    }
+
+    static S32 instanceCount() 
+    { 
+        return LockStatic()->mMap.size(); 
+    }
 
 protected:
-	LLInstanceTracker(const KEY& key) 
-	{ 
-		// make sure static data outlives all instances
-		getStatic();
-		add_(key); 
-	}
-	virtual ~LLInstanceTracker() LLINSTANCETRACKER_DTOR_NOEXCEPT
-	{ 
-		// it's unsafe to delete instances of this type while all instances are being iterated over.
-		llassert_always(getStatic().getDepth() == 0);
-		remove_();
-	}
-	virtual void setKey(KEY key) { remove_(); add_(key); }
-	virtual const KEY& getKey() const { return mInstanceKey; }
+    LLInstanceTracker(const KEY& key) 
+    {
+        // We do not intend to manage the lifespan of this object with
+        // shared_ptr, so give it a no-op deleter. We store shared_ptrs in our
+        // InstanceMap specifically so snapshot can store weak_ptrs so we can
+        // detect deletions during traversals.
+        std::shared_ptr<T> ptr(static_cast<T*>(this), [](T*){});
+        LockStatic lock;
+        add_(lock, key, ptr);
+    }
+public:
+    virtual ~LLInstanceTracker()
+    {
+        LockStatic lock;
+        remove_(lock);
+    }
+protected:
+    virtual void setKey(KEY key)
+    {
+        LockStatic lock;
+        // Even though the shared_ptr we store in our map has a no-op deleter
+        // for T itself, letting the use count decrement to 0 will still
+        // delete the use-count object. Capture the shared_ptr we just removed
+        // and re-add it to the map with the new key.
+        auto ptr = remove_(lock);
+        add_(lock, key, ptr);
+    }
+public:
+    virtual const KEY& getKey() const { return mInstanceKey; }
 
 private:
-	LLInstanceTracker( const LLInstanceTracker& );
-	const LLInstanceTracker& operator=( const LLInstanceTracker& );
-
-	void add_(const KEY& key) 
-	{ 
-		mInstanceKey = key; 
-		InstanceMap& map = getMap_();
-		typename InstanceMap::iterator insertion_point_it = map.lower_bound(key);
-		if (insertion_point_it != map.end() 
-			&& insertion_point_it->first == key)
-		{ // found existing entry with that key
-			switch(KEY_COLLISION_BEHAVIOR)
-			{
-				case LLInstanceTrackerErrorOnCollision:
-				{
-					// use assert here instead of LL_ERRS(), otherwise the error will be ignored since this call is made during global object initialization
-					llassert_always_msg(false, "Instance with this same key already exists!");
-					break;
-				}
-				case LLInstanceTrackerReplaceOnCollision:
-				{
-					// replace pointer, but leave key (should have compared equal anyway)
-					insertion_point_it->second = static_cast<T*>(this);
-					break;
-				}
-				default:
-					break;
-			}
-		}
-		else
-		{ // new key
-			map.insert(insertion_point_it, std::make_pair(key, static_cast<T*>(this)));
-		}
-	}
-	void remove_()
-	{
-		InstanceMap& map = getMap_();
-		typename InstanceMap::iterator iter = map.find(mInstanceKey);
-		if (iter != map.end())
-		{
-			map.erase(iter);
-		}
-	}
+    LLInstanceTracker( const LLInstanceTracker& ) = delete;
+    LLInstanceTracker& operator=( const LLInstanceTracker& ) = delete;
+
+    // for logging
+    template <typename K>
+    static K report(K key) { return key; }
+    static std::string report(const std::string& key) { return "'" + key + "'"; }
+    static std::string report(const char* key) { return report(std::string(key)); }
+
+    // caller must instantiate LockStatic
+    void add_(LockStatic& lock, const KEY& key, const std::shared_ptr<T>& ptr) 
+    { 
+        mInstanceKey = key; 
+        InstanceMap& map = lock->mMap;
+        switch(KEY_COLLISION_BEHAVIOR)
+        {
+        case LLInstanceTrackerErrorOnCollision:
+        {
+            // map stores shared_ptr to self
+            auto pair = map.emplace(key, ptr);
+            if (! pair.second)
+            {
+                LL_ERRS("LLInstanceTracker") << "Instance with key " << report(key)
+                                             << " already exists!" << LL_ENDL;
+            }
+            break;
+        }
+        case LLInstanceTrackerReplaceOnCollision:
+            map[key] = ptr;
+            break;
+        default:
+            break;
+        }
+    }
+    std::shared_ptr<T> remove_(LockStatic& lock)
+    {
+        InstanceMap& map = lock->mMap;
+        typename InstanceMap::iterator iter = map.find(mInstanceKey);
+        if (iter != map.end())
+        {
+            auto ret = iter->second;
+            map.erase(iter);
+            return ret;
+        }
+        return {};
+    }
 
 private:
-	KEY mInstanceKey;
+    KEY mInstanceKey;
 };
 
+/*****************************************************************************
+*   LLInstanceTracker without key
+*****************************************************************************/
+namespace LLInstanceTrackerStuff
+{
+    template <typename VALUE>
+    struct StaticSet: public StaticBase
+    {
+        typedef std::set<VALUE> InstanceSet;
+        InstanceSet mSet;
+    };
+} // LLInstanceTrackerStuff
+
+// TODO:
+// - For the case of omitted KEY template parameter, consider storing
+//   std::map<T*, std::shared_ptr<T>> instead of std::set<std::shared_ptr<T>>.
+//   That might let us share more of the implementation between KEY and
+//   non-KEY LLInstanceTracker subclasses.
+// - Even if not that, consider trying to unify the snapshot implementations.
+//   The trouble is that the 'iterator' published by each (and by their
+//   subclasses) must reflect the specific type of the callables that
+//   distinguish them. (Maybe make instance_snapshot() and key_snapshot()
+//   factory functions that pass lambdas to a factory function for the generic
+//   template class?)
+
 /// explicit specialization for default case where KEY is void
 /// use a simple std::set<T*>
 template<typename T, EInstanceTrackerAllowKeyCollisions KEY_COLLISION_BEHAVIOR>
-class LLInstanceTracker<T, void, KEY_COLLISION_BEHAVIOR> : public LLInstanceTrackerBase
+class LLInstanceTracker<T, void, KEY_COLLISION_BEHAVIOR> :
+    public LLInstanceTrackerBase<LLInstanceTrackerStuff::StaticSet<std::shared_ptr<T>>>
 {
-	typedef LLInstanceTracker<T, void> self_t;
-	typedef typename std::set<T*> InstanceSet;
-	struct StaticData: public StaticBase
-	{
-		InstanceSet sSet;
-	};
-	static StaticData& getStatic() { static StaticData sData; return sData; }
-	static InstanceSet& getSet_() { return getStatic().sSet; }
+    typedef LLInstanceTrackerBase<LLInstanceTrackerStuff::StaticSet<std::shared_ptr<T>>> super;
+    using typename super::StaticData;
+    using typename super::LockStatic;
+    typedef typename StaticData::InstanceSet InstanceSet;
 
 public:
+    /**
+     * Storing a dumb T* somewhere external is a bad idea, since
+     * LLInstanceTracker subclasses are explicitly destroyed rather than
+     * managed by smart pointers. It's legal to declare stack instances of an
+     * LLInstanceTracker subclass. But it's reasonable to store a
+     * std::weak_ptr<T>, which will become invalid when the T instance is
+     * destroyed.
+     */
+    std::weak_ptr<T> getWeak()
+    {
+        return mSelf;
+    }
+    
+    static S32 instanceCount() { return LockStatic()->mSet.size(); }
 
-	/**
-	 * Does a particular instance still exist? Of course, if you already have
-	 * a T* in hand, you need not call getInstance() to @em locate the
-	 * instance -- unlike the case where getInstance() accepts some kind of
-	 * key. Nonetheless this method is still useful to @em validate a
-	 * particular T*, since each instance's destructor removes itself from the
-	 * underlying set.
-	 */
-	static T* getInstance(T* k)
-	{
-		const InstanceSet& set(getSet_());
-		typename InstanceSet::const_iterator found = set.find(k);
-		return (found == set.end())? NULL : *found;
-	}
-	static S32 instanceCount() { return getSet_().size(); }
-
-	class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
-	{
-	public:
-		instance_iter(const typename InstanceSet::iterator& it)
-		:	mIterator(it)
-		{
-			getStatic().incrementDepth();
-		}
-
-		instance_iter(const instance_iter& other)
-		:	mIterator(other.mIterator)
-		{
-			getStatic().incrementDepth();
-		}
-
-		~instance_iter()
-		{
-			getStatic().decrementDepth();
-		}
-
-	private:
-		friend class boost::iterator_core_access;
-
-		void increment() { mIterator++; }
-		bool equal(instance_iter const& other) const
-		{
-			return mIterator == other.mIterator;
-		}
-
-		T& dereference() const
-		{
-			return **mIterator;
-		}
-
-		typename InstanceSet::iterator mIterator;
-	};
-
-	static instance_iter beginInstances() {	return instance_iter(getSet_().begin()); }
-	static instance_iter endInstances() { return instance_iter(getSet_().end()); }
+    // snapshot of std::shared_ptr<T> pointers
+    class snapshot
+    {
+        // It's very important that what we store in this snapshot are
+        // weak_ptrs, NOT shared_ptrs. That's how we discover whether any
+        // instance has been deleted during the lifespan of a snapshot.
+        typedef std::vector<std::weak_ptr<T>> VectorType;
+        // Dereferencing our iterator produces a std::shared_ptr for each
+        // instance that still exists. Since we store weak_ptrs, that involves
+        // two chained transformations:
+        // - a transform_iterator to lock the weak_ptr and return a shared_ptr
+        // - a filter_iterator to skip any shared_ptr that has become invalid.
+        typedef std::shared_ptr<T> strong_ptr;
+        static strong_ptr strengthen(typename VectorType::value_type& ptr)
+        {
+            return ptr.lock();
+        }
+        static bool dead_skipper(const strong_ptr& ptr)
+        {
+            return bool(ptr);
+        }
+
+    public:
+        snapshot():
+            // populate our vector with a snapshot of (locked!) InstanceSet
+            // note, this assigns stored shared_ptrs to weak_ptrs for snapshot
+            mData(mLock->mSet.begin(), mLock->mSet.end())
+        {
+            // release the lock once we've populated mData
+            mLock.unlock();
+        }
+
+        typedef boost::transform_iterator<decltype(strengthen)*,
+                                          typename VectorType::iterator> strong_iterator;
+        typedef boost::filter_iterator<decltype(dead_skipper)*, strong_iterator> iterator;
+
+        iterator begin() { return make_iterator(mData.begin()); }
+        iterator end()   { return make_iterator(mData.end()); }
+
+    private:
+        iterator make_iterator(typename VectorType::iterator iter)
+        {
+            // transform_iterator only needs the base iterator and the transform.
+            // filter_iterator wants the predicate and both ends of the range.
+            return iterator(dead_skipper,
+                            strong_iterator(iter, strengthen),
+                            strong_iterator(mData.end(), strengthen));
+        }
+
+        LockStatic mLock;           // lock static data during construction
+        VectorType mData;
+    };
+
+    // iterate over this for references to each instance
+    struct instance_snapshot: public snapshot
+    {
+        typedef boost::indirect_iterator<typename snapshot::iterator> iterator;
+        iterator begin() { return iterator(snapshot::begin()); }
+        iterator end()   { return iterator(snapshot::end()); }
+
+        void deleteAll()
+        {
+            for (auto it(snapshot::begin()), end(snapshot::end()); it != end; ++it)
+            {
+                delete it->get();
+            }
+        }
+    };
 
 protected:
-	LLInstanceTracker()
-	{
-		// make sure static data outlives all instances
-		getStatic();
-		getSet_().insert(static_cast<T*>(this));
-	}
-	virtual ~LLInstanceTracker() LLINSTANCETRACKER_DTOR_NOEXCEPT
-	{
-		// it's unsafe to delete instances of this type while all instances are being iterated over.
-		llassert_always(getStatic().getDepth() == 0);
-		getSet_().erase(static_cast<T*>(this));
-	}
-
-	LLInstanceTracker(const LLInstanceTracker& other)
-	{
-		getSet_().insert(static_cast<T*>(this));
-	}
+    LLInstanceTracker()
+    {
+        // Since we do not intend for this shared_ptr to manage lifespan, give
+        // it a no-op deleter.
+        std::shared_ptr<T> ptr(static_cast<T*>(this), [](T*){});
+        // save corresponding weak_ptr for future reference
+        mSelf = ptr;
+        // Also store it in our class-static set to track this instance.
+        LockStatic()->mSet.emplace(ptr);
+    }
+public:
+    virtual ~LLInstanceTracker()
+    {
+        // convert weak_ptr to shared_ptr because that's what we store in our
+        // InstanceSet
+        LockStatic()->mSet.erase(mSelf.lock());
+    }
+protected:
+    LLInstanceTracker(const LLInstanceTracker& other):
+        LLInstanceTracker()
+    {}
+
+private:
+    // Storing a weak_ptr to self is a bit like deriving from
+    // std::enable_shared_from_this(), except more explicit.
+    std::weak_ptr<T> mSelf;
 };
 
 #endif
diff --git a/indra/llcommon/llleaplistener.cpp b/indra/llcommon/llleaplistener.cpp
index fa5730f112e2be3eac4aeec79d8a4e49373da179..f50bacb1e8f30b7f519d79b5107d1a0c1e6a93f6 100644
--- a/indra/llcommon/llleaplistener.cpp
+++ b/indra/llcommon/llleaplistener.cpp
@@ -228,13 +228,11 @@ void LLLeapListener::getAPIs(const LLSD& request) const
 {
     Response reply(LLSD(), request);
 
-    for (LLEventAPI::instance_iter eai(LLEventAPI::beginInstances()),
-             eaend(LLEventAPI::endInstances());
-         eai != eaend; ++eai)
+    for (auto& ea : LLEventAPI::instance_snapshot())
     {
         LLSD info;
-        info["desc"] = eai->getDesc();
-        reply[eai->getName()] = info;
+        info["desc"] = ea.getDesc();
+        reply[ea.getName()] = info;
     }
 }
 
diff --git a/indra/llcommon/llthreadlocalstorage.cpp b/indra/llcommon/llthreadlocalstorage.cpp
index 8cef05caac272241f62e8349d1b46315dc4b65c0..d8a063e8d53551c06cfc0f55b101bdd30d3c37a1 100644
--- a/indra/llcommon/llthreadlocalstorage.cpp
+++ b/indra/llcommon/llthreadlocalstorage.cpp
@@ -93,11 +93,9 @@ void LLThreadLocalPointerBase::initAllThreadLocalStorage()
 {
 	if (!sInitialized)
 	{
-		for (LLInstanceTracker<LLThreadLocalPointerBase>::instance_iter it = beginInstances(), end_it = endInstances();
-			it != end_it;
-			++it)
+		for (auto& base : instance_snapshot())
 		{
-			(*it).initStorage();
+			base.initStorage();
 		}
 		sInitialized = true;
 	}
@@ -108,11 +106,9 @@ void LLThreadLocalPointerBase::destroyAllThreadLocalStorage()
 {
 	if (sInitialized)
 	{
-		//for (LLInstanceTracker<LLThreadLocalPointerBase>::instance_iter it = beginInstances(), end_it = endInstances();
-		//	it != end_it;
-		//	++it)
+		//for (auto& base : instance_snapshot())
 		//{
-		//	(*it).destroyStorage();
+		//	base.destroyStorage();
 		//}
 		sInitialized = false;
 	}
diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h
index 79ff55b739888ccbcb45b74b3a2640cf3a2cb93f..0d0cd6f581f1d1832aaa81cd045f1c542575c25a 100644
--- a/indra/llcommon/lltrace.h
+++ b/indra/llcommon/lltrace.h
@@ -57,7 +57,7 @@ class StatBase
 {
 public:
 	StatBase(const char* name, const char* description);
-	virtual ~StatBase() LLINSTANCETRACKER_DTOR_NOEXCEPT	{}
+	virtual ~StatBase()	{}
 	virtual const char* getUnitLabel() const;
 
 	const std::string& getName() const { return mName; }
diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp
index 181fc2f058f4e7b575ce6c363f99367262ce076d..025dc57044d6b8edaad0c8faf343f073a96fa0bc 100644
--- a/indra/llcommon/lltracethreadrecorder.cpp
+++ b/indra/llcommon/lltracethreadrecorder.cpp
@@ -28,6 +28,7 @@
 #include "lltracethreadrecorder.h"
 #include "llfasttimer.h"
 #include "lltrace.h"
+#include "llstl.h"
 
 namespace LLTrace
 {
@@ -64,16 +65,15 @@ void ThreadRecorder::init()
 	activate(&mThreadRecordingBuffers);
 
 	// initialize time block parent pointers
-	for (BlockTimerStatHandle::instance_tracker_t::instance_iter it = BlockTimerStatHandle::instance_tracker_t::beginInstances(), end_it = BlockTimerStatHandle::instance_tracker_t::endInstances(); 
-		it != end_it; 
-		++it)
+	for (auto& base : BlockTimerStatHandle::instance_snapshot())
 	{
-		BlockTimerStatHandle& time_block = static_cast<BlockTimerStatHandle&>(*it);
-		TimeBlockTreeNode& tree_node = mTimeBlockTreeNodes[it->getIndex()];
+		// because of indirect derivation from LLInstanceTracker, have to downcast
+		BlockTimerStatHandle& time_block = static_cast<BlockTimerStatHandle&>(base);
+		TimeBlockTreeNode& tree_node = mTimeBlockTreeNodes[time_block.getIndex()];
 		tree_node.mBlock = &time_block;
 		tree_node.mParent = &root_time_block;
 
-		it->getCurrentAccumulator().mParent = &root_time_block;
+		time_block.getCurrentAccumulator().mParent = &root_time_block;
 	}
 
 	mRootTimer = new BlockTimer(root_time_block);
diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp
index d94fc0c56d0b2052bee78d39a47910f48acd0557..9b8915962525d7bc4272c9c7b3cafda77c527bf7 100644
--- a/indra/llcommon/tests/llinstancetracker_test.cpp
+++ b/indra/llcommon/tests/llinstancetracker_test.cpp
@@ -41,7 +41,6 @@
 #include <boost/scoped_ptr.hpp>
 // other Linden headers
 #include "../test/lltut.h"
-#include "wrapllerrs.h"
 
 struct Badness: public std::runtime_error
 {
@@ -112,24 +111,22 @@ namespace tut
     void object::test<2>()
     {
         ensure_equals(Unkeyed::instanceCount(), 0);
-        Unkeyed* dangling = NULL;
+        std::weak_ptr<Unkeyed> dangling;
         {
             Unkeyed one;
             ensure_equals(Unkeyed::instanceCount(), 1);
-            Unkeyed* found = Unkeyed::getInstance(&one);
-            ensure_equals(found, &one);
+            std::weak_ptr<Unkeyed> found = one.getWeak();
+            ensure(! found.expired());
             {
                 boost::scoped_ptr<Unkeyed> two(new Unkeyed);
                 ensure_equals(Unkeyed::instanceCount(), 2);
-                Unkeyed* found = Unkeyed::getInstance(two.get());
-                ensure_equals(found, two.get());
             }
             ensure_equals(Unkeyed::instanceCount(), 1);
-            // store an unwise pointer to a temp Unkeyed instance
-            dangling = &one;
+            // store a weak pointer to a temp Unkeyed instance
+            dangling = found;
         } // make that instance vanish
         // check the now-invalid pointer to the destroyed instance
-        ensure("getInstance(T*) failed to track destruction", ! Unkeyed::getInstance(dangling));
+        ensure("weak_ptr<Unkeyed> failed to track destruction", dangling.expired());
         ensure_equals(Unkeyed::instanceCount(), 0);
     }
 
@@ -142,7 +139,8 @@ namespace tut
         // reimplement LLInstanceTracker using, say, a hash map instead of a
         // std::map. We DO insist that every key appear exactly once.
         typedef std::vector<std::string> StringVector;
-        StringVector keys(Keyed::beginKeys(), Keyed::endKeys());
+        auto snap = Keyed::key_snapshot();
+        StringVector keys(snap.begin(), snap.end());
         std::sort(keys.begin(), keys.end());
         StringVector::const_iterator ki(keys.begin());
         ensure_equals(*ki++, "one");
@@ -153,17 +151,15 @@ namespace tut
         ensure("didn't reach end", ki == keys.end());
 
         // Use a somewhat different approach to order independence with
-        // beginInstances(): explicitly capture the instances we know in a
+        // instance_snapshot(): explicitly capture the instances we know in a
         // set, and delete them as we iterate through.
         typedef std::set<Keyed*> InstanceSet;
         InstanceSet instances;
         instances.insert(&one);
         instances.insert(&two);
         instances.insert(&three);
-        for (Keyed::instance_iter ii(Keyed::beginInstances()), iend(Keyed::endInstances());
-             ii != iend; ++ii)
+        for (auto& ref : Keyed::instance_snapshot())
         {
-            Keyed& ref = *ii;
             ensure_equals("spurious instance", instances.erase(&ref), 1);
         }
         ensure_equals("unreported instance", instances.size(), 0);
@@ -180,11 +176,10 @@ namespace tut
         instances.insert(&two);
         instances.insert(&three);
 
-		for (Unkeyed::instance_iter ii(Unkeyed::beginInstances()), iend(Unkeyed::endInstances()); ii != iend; ++ii)
-		{
-			Unkeyed& ref = *ii;
-			ensure_equals("spurious instance", instances.erase(&ref), 1);
-		}
+        for (auto& ref : Unkeyed::instance_snapshot())
+        {
+            ensure_equals("spurious instance", instances.erase(&ref), 1);
+        }
 
         ensure_equals("unreported instance", instances.size(), 0);
     }
@@ -192,49 +187,49 @@ namespace tut
     template<> template<>
     void object::test<5>()
     {
-        set_test_name("delete Keyed with outstanding instance_iter");
-        std::string what;
-        Keyed* keyed = new Keyed("delete Keyed with outstanding instance_iter");
-        {
-            WrapLLErrs wrapper;
-            Keyed::instance_iter i(Keyed::beginInstances());
-            what = wrapper.catch_llerrs([&keyed](){
-                    delete keyed;
-                });
-        }
-        ensure(! what.empty());
+        std::string desc("delete Keyed with outstanding instance_snapshot");
+        set_test_name(desc);
+        Keyed* keyed = new Keyed(desc);
+        // capture a snapshot but do not yet traverse it
+        auto snapshot = Keyed::instance_snapshot();
+        // delete the one instance
+        delete keyed;
+        // traversing the snapshot should reflect the deletion
+        // avoid ensure_equals() because it requires the ability to stream the
+        // two values to std::ostream
+        ensure(snapshot.begin() == snapshot.end());
     }
 
     template<> template<>
     void object::test<6>()
     {
-        set_test_name("delete Keyed with outstanding key_iter");
-        std::string what;
-        Keyed* keyed = new Keyed("delete Keyed with outstanding key_it");
-        {
-            WrapLLErrs wrapper;
-            Keyed::key_iter i(Keyed::beginKeys());
-            what = wrapper.catch_llerrs([&keyed](){
-                    delete keyed;
-                });
-        }
-        ensure(! what.empty());
+        std::string desc("delete Keyed with outstanding key_snapshot");
+        set_test_name(desc);
+        Keyed* keyed = new Keyed(desc);
+        // capture a snapshot but do not yet traverse it
+        auto snapshot = Keyed::key_snapshot();
+        // delete the one instance
+        delete keyed;
+        // traversing the snapshot should reflect the deletion
+        // avoid ensure_equals() because it requires the ability to stream the
+        // two values to std::ostream
+        ensure(snapshot.begin() == snapshot.end());
     }
 
     template<> template<>
     void object::test<7>()
     {
-        set_test_name("delete Unkeyed with outstanding instance_iter");
+        set_test_name("delete Unkeyed with outstanding instance_snapshot");
         std::string what;
         Unkeyed* unkeyed = new Unkeyed;
-        {
-            WrapLLErrs wrapper;
-            Unkeyed::instance_iter i(Unkeyed::beginInstances());
-            what = wrapper.catch_llerrs([&unkeyed](){
-                    delete unkeyed;
-                });
-        }
-        ensure(! what.empty());
+        // capture a snapshot but do not yet traverse it
+        auto snapshot = Unkeyed::instance_snapshot();
+        // delete the one instance
+        delete unkeyed;
+        // traversing the snapshot should reflect the deletion
+        // avoid ensure_equals() because it requires the ability to stream the
+        // two values to std::ostream
+        ensure(snapshot.begin() == snapshot.end());
     }
 
     template<> template<>
@@ -246,11 +241,9 @@ namespace tut
         // We can't use the iterator-range InstanceSet constructor because
         // beginInstances() returns an iterator that dereferences to an
         // Unkeyed&, not an Unkeyed*.
-        for (Unkeyed::instance_iter uki(Unkeyed::beginInstances()),
-                                    ukend(Unkeyed::endInstances());
-             uki != ukend; ++uki)
+        for (auto& ref : Unkeyed::instance_snapshot())
         {
-            existing.insert(&*uki);
+            existing.insert(&ref);
         }
         try
         {
@@ -273,11 +266,9 @@ namespace tut
         // instances was also present in the original set. If that's not true,
         // it's because our new Unkeyed ended up in the updated set despite
         // its constructor exception.
-        for (Unkeyed::instance_iter uki(Unkeyed::beginInstances()),
-                                    ukend(Unkeyed::endInstances());
-             uki != ukend; ++uki)
+        for (auto& ref : Unkeyed::instance_snapshot())
         {
-            ensure("failed to remove instance", existing.find(&*uki) != existing.end());
+            ensure("failed to remove instance", existing.find(&ref) != existing.end());
         }
     }
 } // namespace tut
diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp
index bf0a74d10da2d9d1453f94fbb9b39788bf2b0258..9d71e327d88a0a3c5b3e78e7c40b9e3dbbea6e72 100644
--- a/indra/llcommon/tests/llleap_test.cpp
+++ b/indra/llcommon/tests/llleap_test.cpp
@@ -49,24 +49,28 @@ const size_t BUFFERED_LENGTH = 1023*1024; // try wrangling just under a megabyte
 
 #endif
 
-void waitfor(const std::vector<LLLeap*>& instances, int timeout=60)
+// capture std::weak_ptrs to LLLeap instances so we can tell when they expire
+typedef std::vector<std::weak_ptr<LLLeap>> LLLeapVector;
+
+void waitfor(const LLLeapVector& instances, int timeout=60)
 {
     int i;
     for (i = 0; i < timeout; ++i)
     {
         // Every iteration, test whether any of the passed LLLeap instances
         // still exist (are still running).
-        std::vector<LLLeap*>::const_iterator vli(instances.begin()), vlend(instances.end());
-        for ( ; vli != vlend; ++vli)
+        bool found = false;
+        for (auto& ptr : instances)
         {
-            // getInstance() returns NULL if it's terminated/gone, non-NULL if
-            // it's still running
-            if (LLLeap::getInstance(*vli))
+            if (! ptr.expired())
+            {
+                found = true;
                 break;
+            }
         }
         // If we made it through all of 'instances' without finding one that's
         // still running, we're done.
-        if (vli == vlend)
+        if (! found)
         {
 /*==========================================================================*|
             std::cout << instances.size() << " LLLeap instances terminated in "
@@ -86,8 +90,8 @@ void waitfor(const std::vector<LLLeap*>& instances, int timeout=60)
 
 void waitfor(LLLeap* instance, int timeout=60)
 {
-    std::vector<LLLeap*> instances;
-    instances.push_back(instance);
+    LLLeapVector instances;
+    instances.push_back(instance->getWeak());
     waitfor(instances, timeout);
 }
 
@@ -218,11 +222,11 @@ namespace tut
         NamedTempFile script("py",
                              "import time\n"
                              "time.sleep(1)\n");
-        std::vector<LLLeap*> instances;
+        LLLeapVector instances;
         instances.push_back(LLLeap::create(get_test_name(),
-                                           sv(list_of(PYTHON)(script.getName()))));
+                                           sv(list_of(PYTHON)(script.getName())))->getWeak());
         instances.push_back(LLLeap::create(get_test_name(),
-                                           sv(list_of(PYTHON)(script.getName()))));
+                                           sv(list_of(PYTHON)(script.getName())))->getWeak());
         // In this case we're simply establishing that two LLLeap instances
         // can coexist without throwing exceptions or bombing in any other
         // way. Wait for them to terminate.
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index c0f0cec80b2c5e9fc6d84a7d6b0113f980d7784e..a24de45fde02212ad68d1e4fc071a1ee0c889d95 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -2376,9 +2376,8 @@ void LLGLNamePool::release(GLuint name)
 //static
 void LLGLNamePool::upkeepPools()
 {
-	for (tracker_t::instance_iter iter = beginInstances(); iter != endInstances(); ++iter)
+	for (auto& pool : instance_snapshot())
 	{
-		LLGLNamePool & pool = *iter;
 		pool.upkeep();
 	}
 }
@@ -2386,9 +2385,8 @@ void LLGLNamePool::upkeepPools()
 //static
 void LLGLNamePool::cleanupPools()
 {
-	for (tracker_t::instance_iter iter = beginInstances(); iter != endInstances(); ++iter)
+	for (auto& pool : instance_snapshot())
 	{
-		LLGLNamePool & pool = *iter;
 		pool.cleanup();
 	}
 }
diff --git a/indra/llui/llconsole.cpp b/indra/llui/llconsole.cpp
index 5f50e462336424cc88dfcf0473d9a09f01c3c7dc..7817d99aeff0bbee3eabaa4db566f2edb2d55806 100644
--- a/indra/llui/llconsole.cpp
+++ b/indra/llui/llconsole.cpp
@@ -369,9 +369,9 @@ LLConsole::Paragraph::Paragraph (LLWString str, const LLColor4 &color, F32 add_t
 // static
 void LLConsole::updateClass()
 {	
-	for (instance_iter it = beginInstances(); it != endInstances(); ++it)
+	for (auto& con : instance_snapshot())
 	{
-		it->update();
+		con.update();
 	} 
 }
 
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index 4a464b3507ccbd79c1b9cbf6099200ed5a7aa344..4aae1e374b796b4f63d0735f3c725e34794365b9 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -636,10 +636,10 @@ void LLLayoutStack::createResizeBar(LLLayoutPanel* panelp)
 //static 
 void LLLayoutStack::updateClass()
 {
-	for (instance_iter it = beginInstances(); it != endInstances(); ++it)
+	for (auto& layout : instance_snapshot())
 	{
-		it->updateLayout();
-		it->mAnimatedThisFrame = false;
+		layout.updateLayout();
+		layout.mAnimatedThisFrame = false;
 	}
 }
 
diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp
index be26416cbbf958ecb150ba8747d0f729ea05c675..e73ba1fbe90577c65dddcfdae24221a59f991c51 100644
--- a/indra/llui/llnotificationslistener.cpp
+++ b/indra/llui/llnotificationslistener.cpp
@@ -127,18 +127,16 @@ void LLNotificationsListener::listChannels(const LLSD& params) const
 {
     LLReqID reqID(params);
     LLSD response(reqID.makeResponse());
-    for (LLNotificationChannel::instance_iter cmi(LLNotificationChannel::beginInstances()),
-                                              cmend(LLNotificationChannel::endInstances());
-         cmi != cmend; ++cmi)
+    for (auto& cm : LLNotificationChannel::instance_snapshot())
     {
         LLSD channelInfo, parents;
-        BOOST_FOREACH(const std::string& parent, cmi->getParents())
+        for (const std::string& parent : cm.getParents())
         {
             parents.append(parent);
         }
         channelInfo["parents"] = parents;
         channelInfo["parent"] = parents.size()? parents[0] : "";
-        response[cmi->getName()] = channelInfo;
+        response[cm.getName()] = channelInfo;
     }
     LLEventPumps::instance().obtain(params["reply"]).post(response);
 }
diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp
index 1b2425061834bc29321abc8ab1e2070d6483ca01..40e297bac15397fd47d97e0e191331656851952f 100644
--- a/indra/llwindow/llwindow.cpp
+++ b/indra/llwindow/llwindow.cpp
@@ -457,9 +457,9 @@ LLCoordCommon LL_COORD_TYPE_WINDOW::convertToCommon() const
 {
 	const LLCoordWindow& self = LLCoordWindow::getTypedCoords(*this);
 
-	LLWindow* windowp = &(*LLWindow::beginInstances());
+	auto windowit = LLWindow::instance_snapshot().begin();
 	LLCoordGL out;
-	windowp->convertCoords(self, &out);
+	windowit->convertCoords(self, &out);
 	return out.convert();
 }
 
@@ -467,18 +467,18 @@ void LL_COORD_TYPE_WINDOW::convertFromCommon(const LLCoordCommon& from)
 {
 	LLCoordWindow& self = LLCoordWindow::getTypedCoords(*this);
 
-	LLWindow* windowp = &(*LLWindow::beginInstances());
+	auto windowit = LLWindow::instance_snapshot().begin();
 	LLCoordGL from_gl(from);
-	windowp->convertCoords(from_gl, &self);
+	windowit->convertCoords(from_gl, &self);
 }
 
 LLCoordCommon LL_COORD_TYPE_SCREEN::convertToCommon() const
 {
 	const LLCoordScreen& self = LLCoordScreen::getTypedCoords(*this);
 
-	LLWindow* windowp = &(*LLWindow::beginInstances());
+	auto windowit = LLWindow::instance_snapshot().begin();
 	LLCoordGL out;
-	windowp->convertCoords(self, &out);
+	windowit->convertCoords(self, &out);
 	return out.convert();
 }
 
@@ -486,7 +486,7 @@ void LL_COORD_TYPE_SCREEN::convertFromCommon(const LLCoordCommon& from)
 {
 	LLCoordScreen& self = LLCoordScreen::getTypedCoords(*this);
 
-	LLWindow* windowp = &(*LLWindow::beginInstances());
+	auto windowit = LLWindow::instance_snapshot().begin();
 	LLCoordGL from_gl(from);
-	windowp->convertCoords(from_gl, &self);
+	windowit->convertCoords(from_gl, &self);
 }
diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h
index de0d366492fcf475d60695955d8976e975fdd54a..39e1d3e615eb9a7107db4962ba06a0cb0201ae30 100644
--- a/indra/llxml/llcontrol.h
+++ b/indra/llxml/llcontrol.h
@@ -200,8 +200,6 @@ class LLControlGroup : public LLInstanceTracker<LLControlGroup, std::string>
 	LLControlGroup(const std::string& name);
 	~LLControlGroup();
 	void cleanup();
-	
-	typedef LLInstanceTracker<LLControlGroup, std::string>::instance_iter instance_iter;
 
 	LLControlVariablePtr getControl(const std::string& name);
 
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index b232a8c3bbfeb3bc6002aa8da53ef1f422c61065..a76ac5872430e890a1895cb9db43e922061b360a 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1681,24 +1681,9 @@ bool LLAppViewer::cleanup()
 		gDirUtilp->deleteFilesInDir(logdir, "*-*-*-*-*.dmp");
 	}
 
-	{
-		// Kill off LLLeap objects. We can find them all because LLLeap is derived
-		// from LLInstanceTracker. But collect instances first: LLInstanceTracker
-		// specifically forbids adding/deleting instances while iterating.
-		std::vector<LLLeap*> leaps;
-		leaps.reserve(LLLeap::instanceCount());
-		for (LLLeap::instance_iter li(LLLeap::beginInstances()), lend(LLLeap::endInstances());
-			 li != lend; ++li)
-		{
-			leaps.push_back(&*li);
-		}
-		// Okay, now trash them all. We don't have to NULL or erase the entry
-		// in 'leaps' because the whole vector is going away momentarily.
-		BOOST_FOREACH(LLLeap* leap, leaps)
-		{
-			delete leap;
-		}
-	} // destroy 'leaps'
+	// Kill off LLLeap objects. We can find them all because LLLeap is derived
+	// from LLInstanceTracker.
+	LLLeap::instance_snapshot().deleteAll();
 
 	//flag all elements as needing to be destroyed immediately
 	// to ensure shutdown order
@@ -2858,12 +2843,11 @@ bool LLAppViewer::initConfiguration()
 
 	// Let anyone else who cares know that we've populated our settings
 	// variables.
-	for (LLControlGroup::key_iter ki(LLControlGroup::beginKeys()), kend(LLControlGroup::endKeys());
-		 ki != kend; ++ki)
+	for (const auto& key : LLControlGroup::key_snapshot())
 	{
 		// For each named instance of LLControlGroup, send an event saying
 		// we've initialized an LLControlGroup instance by that name.
-		LLEventPumps::instance().obtain("LLControlGroup").post(LLSDMap("init", *ki));
+		LLEventPumps::instance().obtain("LLControlGroup").post(LLSDMap("init", key));
 	}
 
 	return true; // Config was successful.
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index 1099d4bc09e1481233d1c41b3a64656ff5a5979f..4131af828e4d4f5cf14bd6fab1b0fe8d3ab27436 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -1344,10 +1344,8 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
 				// We don't want multiple friendship offers to appear, this code checks if there are previous offers
 				// by iterating though all panels.
 				// Note: it might be better to simply add a "pending offer" flag somewhere
-				for (LLToastNotifyPanel::instance_iter ti(LLToastNotifyPanel::beginInstances())
-					, tend(LLToastNotifyPanel::endInstances()); ti != tend; ++ti)
+				for (auto& panel : LLToastNotifyPanel::instance_snapshot())
 				{
-					LLToastNotifyPanel& panel = *ti;
 					LLIMToastNotifyPanel * imtoastp = dynamic_cast<LLIMToastNotifyPanel *>(&panel);
 					const std::string& notification_name = panel.getNotificationName();
 					if (notification_name == "OfferFriendship"
diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp
index c3375a377967215d434c1d48d801f5215a2a524b..c1dcc61010e08afd29388c14f96212c7bbdac238 100644
--- a/indra/newview/llimprocessing.cpp
+++ b/indra/newview/llimprocessing.cpp
@@ -1404,10 +1404,8 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
             payload["sender"] = sender.getIPandPort();
 
             bool add_notification = true;
-            for (LLToastNotifyPanel::instance_iter ti(LLToastNotifyPanel::beginInstances())
-                , tend(LLToastNotifyPanel::endInstances()); ti != tend; ++ti)
+            for (auto& panel : LLToastNotifyPanel::instance_snapshot())
             {
-                LLToastNotifyPanel& panel = *ti;
                 const std::string& notification_name = panel.getNotificationName();
                 if (notification_name == "OfferFriendship" && panel.isControlPanelEnabled())
                 {
diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp
index 5ab00130557223c47a49007bc808e39951ed18c5..2c0c38dc75b04d4b16b2f5d2ae57ba3277a5a66b 100644
--- a/indra/newview/llscenemonitor.cpp
+++ b/indra/newview/llscenemonitor.cpp
@@ -559,16 +559,14 @@ void LLSceneMonitor::dumpToFile(std::string file_name)
 
 
 	typedef StatType<CountAccumulator> trace_count;
-	for (trace_count::instance_iter it = trace_count::beginInstances(), end_it = trace_count::endInstances();
-		it != end_it;
-		++it)
+	for (auto& it : trace_count::instance_snapshot())
 	{
 		std::ostringstream row;
 		row << std::setprecision(10);
 
-		row << it->getName();
+		row << it.getName();
 
-		const char* unit_label = it->getUnitLabel();
+		const char* unit_label = it.getUnitLabel();
 		if(unit_label[0])
 		{
 			row << "(" << unit_label << ")";
@@ -579,8 +577,8 @@ void LLSceneMonitor::dumpToFile(std::string file_name)
 		for (S32 frame = 1; frame <= frame_count; frame++)
 		{
 			Recording& recording = scene_load_recording.getPrevRecording(frame_count - frame);
-			samples += recording.getSampleCount(*it);
-			row << ", " << recording.getSum(*it);
+			samples += recording.getSampleCount(it);
+			row << ", " << recording.getSum(it);
 		}
 
 		row << '\n';
@@ -593,15 +591,13 @@ void LLSceneMonitor::dumpToFile(std::string file_name)
 
 	typedef StatType<EventAccumulator> trace_event;
 
-	for (trace_event::instance_iter it = trace_event::beginInstances(), end_it = trace_event::endInstances();
-		it != end_it;
-		++it)
+	for (auto& it : trace_event::instance_snapshot())
 	{
 		std::ostringstream row;
 		row << std::setprecision(10);
-		row << it->getName();
+		row << it.getName();
 
-		const char* unit_label = it->getUnitLabel();
+		const char* unit_label = it.getUnitLabel();
 		if(unit_label[0])
 		{
 			row << "(" << unit_label << ")";
@@ -612,8 +608,8 @@ void LLSceneMonitor::dumpToFile(std::string file_name)
 		for (S32 frame = 1; frame <= frame_count; frame++)
 		{
 			Recording& recording = scene_load_recording.getPrevRecording(frame_count - frame);
-			samples += recording.getSampleCount(*it);
-			F64 mean = recording.getMean(*it);
+			samples += recording.getSampleCount(it);
+			F64 mean = recording.getMean(it);
 			if (llisnan(mean))
 			{
 				row << ", n/a";
@@ -634,15 +630,13 @@ void LLSceneMonitor::dumpToFile(std::string file_name)
 
 	typedef StatType<SampleAccumulator> trace_sample;
 
-	for (trace_sample::instance_iter it = trace_sample::beginInstances(), end_it = trace_sample::endInstances();
-		it != end_it;
-		++it)
+	for (auto& it : trace_sample::instance_snapshot())
 	{
 		std::ostringstream row;
 		row << std::setprecision(10);
-		row << it->getName();
+		row << it.getName();
 
-		const char* unit_label = it->getUnitLabel();
+		const char* unit_label = it.getUnitLabel();
 		if(unit_label[0])
 		{
 			row << "(" << unit_label << ")";
@@ -653,8 +647,8 @@ void LLSceneMonitor::dumpToFile(std::string file_name)
 		for (S32 frame = 1; frame <= frame_count; frame++)
 		{
 			Recording& recording = scene_load_recording.getPrevRecording(frame_count - frame);
-			samples += recording.getSampleCount(*it);
-			F64 mean = recording.getMean(*it);
+			samples += recording.getSampleCount(it);
+			F64 mean = recording.getMean(it);
 			if (llisnan(mean))
 			{
 				row << ", n/a";
@@ -674,15 +668,13 @@ void LLSceneMonitor::dumpToFile(std::string file_name)
 	}
 
 	typedef StatType<MemAccumulator> trace_mem;
-	for (trace_mem::instance_iter it = trace_mem::beginInstances(), end_it = trace_mem::endInstances();
-		it != end_it;
-		++it)
+	for (auto& it : trace_mem::instance_snapshot())
 	{
-		os << it->getName() << "(KiB)";
+		os << it.getName() << "(KiB)";
 
 		for (S32 frame = 1; frame <= frame_count; frame++)
 		{
-			os << ", " << scene_load_recording.getPrevRecording(frame_count - frame).getMax(*it).valueInUnits<LLUnits::Kilobytes>();
+			os << ", " << scene_load_recording.getPrevRecording(frame_count - frame).getMax(it).valueInUnits<LLUnits::Kilobytes>();
 		}
 
 		os << '\n';
diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp
index 870e0d94f0c03518b6dda3e5924ea5382afe378a..bf56a10d4d343ec5441d8b64668ca31863f3bb2b 100644
--- a/indra/newview/lltoast.cpp
+++ b/indra/newview/lltoast.cpp
@@ -612,11 +612,8 @@ S32	LLToast::notifyParent(const LLSD& info)
 //static
 void LLToast::updateClass()
 {
-	for (LLInstanceTracker<LLToast>::instance_iter iter = LLInstanceTracker<LLToast>::beginInstances(); 
-			iter != LLInstanceTracker<LLToast>::endInstances(); ) 
+	for (auto& toast : LLInstanceTracker<LLToast>::instance_snapshot())
 	{
-		LLToast& toast = *iter++;
-		
 		toast.updateHoveredState();
 	}
 }
@@ -624,22 +621,6 @@ void LLToast::updateClass()
 // static 
 void LLToast::cleanupToasts()
 {
-	LLToast * toastp = NULL;
-
-	while (LLInstanceTracker<LLToast>::instanceCount() > 0)
-	{
-		{	// Need to scope iter to allow deletion
-			LLInstanceTracker<LLToast>::instance_iter iter = LLInstanceTracker<LLToast>::beginInstances(); 
-			toastp = &(*iter);
-		}
-
-		//LL_INFOS() << "Cleaning up toast id " << toastp->getNotificationID() << LL_ENDL;
-
-		// LLToast destructor will remove it from the LLInstanceTracker.
-		if (!toastp)
-			break;		// Don't get stuck in the loop if a null pointer somehow got on the list
-
-		delete toastp;
-	}
+	LLInstanceTracker<LLToast>::instance_snapshot().deleteAll();
 }
 
diff --git a/indra/newview/llviewercontrollistener.cpp b/indra/newview/llviewercontrollistener.cpp
index d2484b2b233a8b766c360cdfec90d84734c5aaf0..3443bb644a1e2cf507a58a6960a3ad909467a167 100644
--- a/indra/newview/llviewercontrollistener.cpp
+++ b/indra/newview/llviewercontrollistener.cpp
@@ -50,11 +50,9 @@ LLViewerControlListener::LLViewerControlListener()
 	std::ostringstream groupnames;
 	groupnames << "[\"group\"] is one of ";
 	const char* delim = "";
-	for (LLControlGroup::key_iter cgki(LLControlGroup::beginKeys()),
-								  cgkend(LLControlGroup::endKeys());
-		 cgki != cgkend; ++cgki)
+	for (const auto& key : LLControlGroup::key_snapshot())
 	{
-		groupnames << delim << '"' << *cgki << '"';
+		groupnames << delim << '"' << key << '"';
 		delim = ", ";
 	}
 	groupnames << '\n';
@@ -181,11 +179,9 @@ void LLViewerControlListener::groups(LLSD const & request)
 {
 	// No Info, we're not looking up either a group or a control name.
 	Response response(LLSD(), request);
-	for (LLControlGroup::key_iter cgki(LLControlGroup::beginKeys()),
-								  cgkend(LLControlGroup::endKeys());
-		 cgki != cgkend; ++cgki)
+	for (const auto& key : LLControlGroup::key_snapshot())
 	{
-		response["groups"].append(*cgki);
+		response["groups"].append(key);
 	}
 }