diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index 555164f3b001c2fe46ad3d855008d8fc1fe52011..444d9a5366ef2f0a83c1d25f38c16542024b8073 100644
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -1389,6 +1389,16 @@ LLMeshSkinInfo::LLMeshSkinInfo(LLSD& skin):
 	fromLLSD(skin);
 }
 
+LLMeshSkinInfo::LLMeshSkinInfo(const LLUUID& mesh_id, LLSD& skin) :
+	mMeshID(mesh_id),
+	mPelvisOffset(0.0),
+	mLockScaleIfJointPosition(false),
+	mInvalidJointsScrubbed(false),
+	mJointNumsInitialized(false)
+{
+	fromLLSD(skin);
+}
+
 void LLMeshSkinInfo::fromLLSD(LLSD& skin)
 {
 	if (skin.has("joint_names"))
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index a6ab96ab18400dcfd57c02064a1bc1eb6bbbdcdf..9c99bb75a0be3495602fa9cb2a112feede09c328 100644
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -41,12 +41,13 @@ class domMesh;
 #define MAX_MODEL_FACES 8
 
 LL_ALIGN_PREFIX(16)
-class LLMeshSkinInfo 
+class LLMeshSkinInfo : public LLRefCount
 {
     LL_ALIGN_NEW
 public:
 	LLMeshSkinInfo();
 	LLMeshSkinInfo(LLSD& data);
+	LLMeshSkinInfo(const LLUUID& mesh_id, LLSD& data);
 	void fromLLSD(LLSD& data);
 	LLSD asLLSD(bool include_joints, bool lock_scale_if_joint_position) const;
     void updateHash();
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index d5b14dc6aae6f4b7cad612ce8fc4d430042116d8..ced64b655e77b5e854631875e8cde57a7ec4e3a4 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -1972,8 +1972,16 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat
 	}
 	
 	{
-		LLMeshSkinInfo info(skin);
-		info.mMeshID = mesh_id;
+		LLMeshSkinInfo* info = nullptr;
+		try
+		{
+			info = new LLMeshSkinInfo(mesh_id, skin);
+		}
+		catch (const std::bad_alloc& ex)
+		{
+			LL_WARNS() << "Failed to allocate skin info with exception: " << ex.what()  << LL_ENDL;
+			return false;
+		}
 
         // LL_DEBUGS(LOG_MESH) << "info pelvis offset" << info.mPelvisOffset << LL_ENDL;
 		{
@@ -2898,7 +2906,7 @@ void LLMeshRepoThread::notifyLoadedMeshes()
 	{
 		if (mMutex->trylock())
 		{
-			std::list<LLMeshSkinInfo> skin_info_q;
+			std::list<LLMeshSkinInfo*> skin_info_q;
 			std::list<LLModel::Decomposition*> decomp_q;
 
 			if (! mSkinInfoQ.empty())
@@ -3491,7 +3499,7 @@ LLMeshRepository::LLMeshRepository()
   mMeshThreadCount(0),
   mThread(NULL)
 {
-
+	mSkinInfoCullTimer.resetWithExpiry(10.f);
 }
 
 void LLMeshRepository::init()
@@ -3776,6 +3784,28 @@ void LLMeshRepository::notifyLoadedMeshes()
 	//call completed callbacks on finished decompositions
 	mDecompThread->notifyCompleted();
 
+	if (mSkinInfoCullTimer.checkExpirationAndReset(10.f)) 
+	{
+		//// Clean up dead skin info
+		//U64Bytes skinbytes(0);
+		for (auto iter = mSkinMap.begin(), ender = mSkinMap.end(); iter != ender;)
+		{
+			auto copy_iter = iter++;
+
+			//skinbytes += U64Bytes(sizeof(LLMeshSkinInfo));
+			//skinbytes += U64Bytes(copy_iter->second->mJointNames.size() * sizeof(std::string));
+			//skinbytes += U64Bytes(copy_iter->second->mJointNums.size() * sizeof(S32));
+			//skinbytes += U64Bytes(copy_iter->second->mJointNames.size() * sizeof(LLMatrix4a));
+			//skinbytes += U64Bytes(copy_iter->second->mJointNames.size() * sizeof(LLMatrix4));
+
+			if (copy_iter->second->getNumRefs() == 1)
+			{
+				mSkinMap.erase(copy_iter);
+			}
+		}
+		//LL_INFOS() << "Skin info cache elements:" << mSkinMap.size() << " Memory: " << U64Kilobytes(skinbytes) << LL_ENDL;
+	}
+
 	// For major operations, attempt to get the required locks
 	// without blocking and punt if they're not available.  The
 	// longest run of holdoffs is kept in sMaxLockHoldoffs just
@@ -3913,13 +3943,13 @@ void LLMeshRepository::notifyLoadedMeshes()
 	mThread->mSignal->signal();
 }
 
-void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo& info)
+void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo* info)
 {
-	mSkinMap[info.mMeshID] = info;
+	mSkinMap[info->mMeshID] = info; // Cache into LLPointer
     // Alternative: We can get skin size from header
-    sCacheBytesSkins += info.sizeBytes();
+    sCacheBytesSkins += info->sizeBytes();
 
-	skin_load_map::iterator iter = mLoadingSkins.find(info.mMeshID);
+	skin_load_map::iterator iter = mLoadingSkins.find(info->mMeshID);
 	if (iter != mLoadingSkins.end())
 	{
 		for (std::set<LLUUID>::iterator obj_id = iter->second.begin(); obj_id != iter->second.end(); ++obj_id)
@@ -3927,10 +3957,27 @@ void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo& info)
 			LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*obj_id);
 			if (vobj)
 			{
-				vobj->notifyMeshLoaded();
+				vobj->notifySkinInfoLoaded(info);
+			}
+		}
+		mLoadingSkins.erase(iter);
+	}
+}
+
+void LLMeshRepository::notifySkinInfoUnavailable(const LLUUID& mesh_id)
+{
+	skin_load_map::iterator iter = mLoadingSkins.find(mesh_id);
+	if (iter != mLoadingSkins.end())
+	{
+		for (std::set<LLUUID>::iterator obj_id = iter->second.begin(); obj_id != iter->second.end(); ++obj_id)
+		{
+			LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*obj_id);
+			if (vobj)
+			{
+				vobj->notifySkinInfoUnavailable();
 			}
 		}
-		mLoadingSkins.erase(info.mMeshID);
+		mLoadingSkins.erase(iter);
 	}
 }
 
@@ -4042,7 +4089,7 @@ const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const
         skin_map::iterator iter = mSkinMap.find(mesh_id);
         if (iter != mSkinMap.end())
         {
-            return &(iter->second);
+            return iter->second;
         }
 
         //no skin info known about given mesh, try to fetch it
@@ -4058,7 +4105,7 @@ const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const
             mLoadingSkins[mesh_id].insert(requesting_obj->getID());
         }
     }
-	return NULL;
+	return nullptr;
 }
 
 void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index 2cade8f01eeb8103eba3ce30af12a790f3a76667..a5b985ee76394bc07cdf5907005599876d88a92d 100644
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -284,7 +284,7 @@ class LLMeshRepoThread : public LLThread
 	std::set<UUIDBasedRequest> mSkinRequests;
 	
 	// list of completed skin info requests
-	std::list<LLMeshSkinInfo> mSkinInfoQ;
+	std::list<LLMeshSkinInfo*> mSkinInfoQ;
 
 	//set of requested decompositions
 	std::set<UUIDBasedRequest> mDecompositionRequests;
@@ -581,7 +581,8 @@ class LLMeshRepository
 	void notifyLoadedMeshes();
 	void notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume);
 	void notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod);
-	void notifySkinInfoReceived(LLMeshSkinInfo& info);
+	void notifySkinInfoReceived(LLMeshSkinInfo* info);
+	void notifySkinInfoUnavailable(const LLUUID& info);
 	void notifyDecompositionReceived(LLModel::Decomposition* info);
 
 	S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
@@ -614,7 +615,7 @@ class LLMeshRepository
 	typedef boost::unordered_map<LLUUID, std::vector<LLUUID> > mesh_load_map;
 	mesh_load_map mLoadingMeshes[4];
 	
-	typedef std::unordered_map<LLUUID, LLMeshSkinInfo> skin_map;
+	typedef std::unordered_map<LLUUID, LLPointer<LLMeshSkinInfo>> skin_map;
 	skin_map mSkinMap;
 
 	typedef std::map<LLUUID, LLModel::Decomposition*> decomposition_map;
@@ -650,6 +651,8 @@ class LLMeshRepository
 	std::vector<LLMeshUploadThread*> mUploadWaitList;
 
 	LLPhysicsDecomp* mDecompThread;
+
+	LLFrameTimer     mSkinInfoCullTimer;
 	
 	class inventory_data
 	{
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index f4a938e57dce4d5244d50e84112432b75b32e731..d5583f05f37143851c1c97889f68b164605d807a 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -228,6 +228,9 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re
     mColorChanged = FALSE;
 	mSpotLightPriority = 0.f;
 
+	mSkinInfoFailed = false;
+	mSkinInfo = NULL;
+
 	mMediaImplList.resize(getNumTEs());
 	mLastFetchedMediaVersion = -1;
     mServerDrawableUpdateCount = 0;
@@ -1095,6 +1098,12 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &params_in, const S32 detail, bo
 			// if it's a mesh
 			if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
 			{
+				if (mSkinInfo && mSkinInfo->mMeshID != volume_params.getSculptID())
+				{
+					mSkinInfo = NULL;
+					mSkinInfoFailed = false;
+				}
+
 				if (!getVolume()->isMeshAssetLoaded())
 				{ 
 					//load request not yet issued, request pipeline load this mesh
@@ -1106,6 +1115,14 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &params_in, const S32 detail, bo
 					}
 				}
 				
+				if (!mSkinInfo && !mSkinInfoFailed)
+				{
+					const LLMeshSkinInfo* skin_info = gMeshRepo.getSkinInfo(volume_params.getSculptID(), this);
+					if (skin_info)
+					{
+						notifySkinInfoLoaded(skin_info);
+					}
+				}
 			}
 			else // otherwise is sculptie
 			{
@@ -1158,6 +1175,9 @@ void LLVOVolume::updateSculptTexture()
 		{
 			mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
 		}
+
+		mSkinInfoFailed = false;
+		mSkinInfo = NULL;
 	}
 	else
 	{
@@ -1212,6 +1232,20 @@ void LLVOVolume::notifyMeshLoaded()
     updateVisualComplexity();
 }
 
+void LLVOVolume::notifySkinInfoLoaded(const LLMeshSkinInfo* skin)
+{
+	mSkinInfoFailed = false;
+	mSkinInfo = skin;
+
+	notifyMeshLoaded();
+}
+
+void LLVOVolume::notifySkinInfoUnavailable()
+{
+	mSkinInfoFailed = true;
+	mSkinInfo = nullptr;
+}
+
 // sculpt replaces generate() for sculpted surfaces
 void LLVOVolume::sculpt()
 {	
@@ -3645,7 +3679,7 @@ const LLMeshSkinInfo* LLVOVolume::getSkinInfo() const
 {
     if (getVolume())
     {
-        return gMeshRepo.getSkinInfo(getMeshID(), this);
+         return mSkinInfo;
     }
     else
     {
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 4136c13315aa0a82a39967a4cf738e78f9d4bf05..12681e2bd9ddde665b5d6efccf865597a5a2a521 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -350,6 +350,8 @@ class LLVOVolume : public LLViewerObject
     void updateVisualComplexity();
     
 	void notifyMeshLoaded();
+	void notifySkinInfoLoaded(const LLMeshSkinInfo* skin);
+	void notifySkinInfoUnavailable();
 	
 	// Returns 'true' iff the media data for this object is in flight
 	bool isMediaDataBeingFetched() const;
@@ -433,6 +435,8 @@ class LLVOVolume : public LLViewerObject
 
 	LLPointer<LLRiggedVolume> mRiggedVolume;
 
+	bool mSkinInfoFailed;
+	LLConstPointer<LLMeshSkinInfo> mSkinInfo;
 	// statics
 public:
 	static F32 sLODSlopDistanceFactor;// Changing this to zero, effectively disables the LOD transition slop