diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index e5af47ab6cb69111f161585c53e9700b2bd1bed7..99696318438ba1aa7ab0188679b873e43ee46263 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -53,6 +53,7 @@ const F32 TEXTURE_CACHE_PURGE_AMOUNT = .20f; // % amount to reduce the cache by
 const F32 TEXTURE_CACHE_LRU_SIZE = .10f; // % amount for LRU list (low overhead to regenerate)
 const S32 TEXTURE_FAST_CACHE_ENTRY_OVERHEAD = sizeof(S32) * 4; //w, h, c, level
 const S32 TEXTURE_FAST_CACHE_ENTRY_SIZE = 16 * 16 * 4 + TEXTURE_FAST_CACHE_ENTRY_OVERHEAD;
+const F32 TEXTURE_LAZY_PURGE_TIME_LIMIT = .005f; // 5ms
 
 class LLTextureCacheWorker : public LLWorkerClass
 {
@@ -1669,6 +1670,90 @@ void LLTextureCache::purgeAllTextures(bool purge_directories)
 	LL_INFOS() << "The entire texture cache is cleared." << LL_ENDL ;
 }
 
+void LLTextureCache::purgeTexturesLazy(F32 time_limit_sec)
+{
+	if (mReadOnly)
+	{
+		return;
+	}
+
+	if (!mThreaded)
+	{
+		LLAppViewer::instance()->pauseMainloopTimeout();
+	}
+
+	// time_limit doesn't account for lock time
+	LLMutexLock lock(&mHeaderMutex);
+
+	if (mPurgeEntryList.empty())
+	{
+		// Read the entries list and form list of textures to purge
+		std::vector<Entry> entries;
+		U32 num_entries = openAndReadEntries(entries);
+		if (!num_entries)
+		{
+			return; // nothing to purge
+		}
+
+		// Use mTexturesSizeMap to collect UUIDs of textures with bodies
+		typedef std::set<std::pair<U32, S32> > time_idx_set_t;
+		std::set<std::pair<U32, S32> > time_idx_set;
+		for (size_map_t::iterator iter1 = mTexturesSizeMap.begin();
+			iter1 != mTexturesSizeMap.end(); ++iter1)
+		{
+			if (iter1->second > 0)
+			{
+				id_map_t::iterator iter2 = mHeaderIDMap.find(iter1->first);
+				if (iter2 != mHeaderIDMap.end())
+				{
+					S32 idx = iter2->second;
+					time_idx_set.insert(std::make_pair(entries[idx].mTime, idx));
+				}
+				else
+				{
+					LL_ERRS("TextureCache") << "mTexturesSizeMap / mHeaderIDMap corrupted." << LL_ENDL;
+				}
+			}
+		}
+
+		S64 cache_size = mTexturesSizeTotal;
+		S64 purged_cache_size = (sCacheMaxTexturesSize * (S64)((1.f - TEXTURE_CACHE_PURGE_AMOUNT) * 100)) / 100;
+		for (time_idx_set_t::iterator iter = time_idx_set.begin();
+			iter != time_idx_set.end(); ++iter)
+		{
+			S32 idx = iter->second;
+			if (cache_size >= purged_cache_size)
+			{
+				cache_size -= entries[idx].mBodySize;
+				mPurgeEntryList.push_back(std::pair<S32, Entry>(idx, entries[idx]));
+			}
+			else
+			{
+				break;
+			}
+		}
+		LL_DEBUGS("TextureCache") << "Formed Purge list of " << mPurgeEntryList.size() << " entries" << LL_ENDL;
+	}
+	else
+	{
+		// Remove collected entried
+		LLTimer timer;
+		while (!mPurgeEntryList.empty() && timer.getElapsedTimeF32() < time_limit_sec)
+		{
+			S32 idx = mPurgeEntryList.back().first;
+			Entry entry = mPurgeEntryList.back().second;
+			mPurgeEntryList.pop_back();
+			// make sure record is still valid
+			id_map_t::iterator iter_header = mHeaderIDMap.find(entry.mID);
+			if (iter_header != mHeaderIDMap.end() && iter_header->second == idx)
+			{
+				removeEntry(idx, entry, getTextureFileName(entry.mID));
+				writeEntryToHeaderImmediately(idx, entry);
+			}
+		}
+	}
+}
+
 void LLTextureCache::purgeTextures(bool validate)
 {
 	if (mReadOnly)
@@ -1928,11 +2013,10 @@ LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 prio
 	}
 	if (mDoPurge)
 	{
-		// NOTE: This may cause an occasional hiccup,
-		//  but it really needs to be done on the control thread
-		//  (i.e. here)		
-		purgeTextures(false);
-		mDoPurge = FALSE;
+		// NOTE: Needs to be done on the control thread
+		//  (i.e. here)
+		purgeTexturesLazy(TEXTURE_LAZY_PURGE_TIME_LIMIT);
+		mDoPurge = !mPurgeEntryList.empty();
 	}
 	LLMutexLock lock(&mWorkersMutex);
 	LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id,
diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h
index 81ea7aeee2d98057c70f25b486bfc45b95af1d5e..9f68aa90393776f48463670c5faed486d641df7b 100644
--- a/indra/newview/lltexturecache.h
+++ b/indra/newview/lltexturecache.h
@@ -155,6 +155,7 @@ class LLTextureCache : public LLWorkerThread
 	void readHeaderCache();
 	void clearCorruptedCache();
 	void purgeAllTextures(bool purge_directories);
+	void purgeTexturesLazy(F32 time_limit_sec);
 	void purgeTextures(bool validate);
 	LLAPRFile* openHeaderEntriesFile(bool readonly, S32 offset);
 	void closeHeaderEntriesFile();
@@ -225,6 +226,8 @@ class LLTextureCache : public LLWorkerThread
 
 	typedef std::map<S32, Entry> idx_entry_map_t;
 	idx_entry_map_t mUpdatedEntryMap;
+	typedef std::vector<std::pair<S32, Entry>> idx_entry_vector_t;
+	idx_entry_vector_t mPurgeEntryList;
 
 	// Statics
 	static F32 sHeaderCacheVersion;