fix for VWR-26864: Recent commit to Snowstorm project introduces frequent errors and crashes associated with private memory pool.
parent
82b1b1bc6e
commit
616a7b549d
|
|
@ -165,33 +165,60 @@ void LLMemory::logMemoryInfo(BOOL update)
|
|||
llinfos << "Current allocated page size (KB): " << sAllocatedPageSizeInKB << llendl ;
|
||||
llinfos << "Current availabe physical memory(KB): " << sAvailPhysicalMemInKB << llendl ;
|
||||
llinfos << "Current max usable memory(KB): " << sMaxPhysicalMemInKB << llendl ;
|
||||
|
||||
llinfos << "--- private pool information -- " << llendl ;
|
||||
llinfos << "Total reserved (KB): " << LLPrivateMemoryPoolManager::getInstance()->mTotalReservedSize / 1024 << llendl ;
|
||||
llinfos << "Total allocated (KB): " << LLPrivateMemoryPoolManager::getInstance()->mTotalAllocatedSize / 1024 << llendl ;
|
||||
}
|
||||
|
||||
//return 0: everything is normal;
|
||||
//return 1: the memory pool is low, but not in danger;
|
||||
//return -1: the memory pool is in danger, is about to crash.
|
||||
//static
|
||||
S32 LLMemory::isMemoryPoolLow()
|
||||
bool LLMemory::isMemoryPoolLow()
|
||||
{
|
||||
static const U32 LOW_MEMEOY_POOL_THRESHOLD_KB = 64 * 1024 ; //64 MB for emergency use
|
||||
const static U32 MAX_SIZE_CHECKED_MEMORY_BLOCK = 64 * 1024 * 1024 ; //64 MB
|
||||
static void* last_reserved_address = NULL ;
|
||||
|
||||
if(!sEnableMemoryFailurePrevention)
|
||||
{
|
||||
return 0 ; //no memory failure prevention.
|
||||
return false ; //no memory failure prevention.
|
||||
}
|
||||
|
||||
if(sAvailPhysicalMemInKB < (LOW_MEMEOY_POOL_THRESHOLD_KB >> 2)) //out of physical memory
|
||||
{
|
||||
return -1 ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
if(sAllocatedPageSizeInKB + (LOW_MEMEOY_POOL_THRESHOLD_KB >> 2) > sMaxHeapSizeInKB) //out of virtual address space.
|
||||
{
|
||||
return -1 ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
return (S32)(sAvailPhysicalMemInKB < LOW_MEMEOY_POOL_THRESHOLD_KB ||
|
||||
bool is_low = (S32)(sAvailPhysicalMemInKB < LOW_MEMEOY_POOL_THRESHOLD_KB ||
|
||||
sAllocatedPageSizeInKB + LOW_MEMEOY_POOL_THRESHOLD_KB > sMaxHeapSizeInKB) ;
|
||||
|
||||
//check the virtual address space fragmentation
|
||||
if(!is_low)
|
||||
{
|
||||
if(!last_reserved_address)
|
||||
{
|
||||
last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK) ;
|
||||
if(!last_reserved_address) //failed, try once more
|
||||
{
|
||||
last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK) ;
|
||||
}
|
||||
}
|
||||
|
||||
is_low = !last_reserved_address ; //allocation failed
|
||||
}
|
||||
|
||||
return is_low ;
|
||||
}
|
||||
|
||||
//static
|
||||
|
|
@ -1289,15 +1316,13 @@ U16 LLPrivateMemoryPool::LLMemoryChunk::getPageLevel(U32 size)
|
|||
//--------------------------------------------------------------------
|
||||
const U32 CHUNK_SIZE = 4 << 20 ; //4 MB
|
||||
const U32 LARGE_CHUNK_SIZE = 4 * CHUNK_SIZE ; //16 MB
|
||||
LLPrivateMemoryPool::LLPrivateMemoryPool(S32 type) :
|
||||
LLPrivateMemoryPool::LLPrivateMemoryPool(S32 type, U32 max_pool_size) :
|
||||
mMutexp(NULL),
|
||||
mReservedPoolSize(0),
|
||||
mHashFactor(1),
|
||||
mType(type)
|
||||
mType(type),
|
||||
mMaxPoolSize(max_pool_size)
|
||||
{
|
||||
const U32 MAX_POOL_SIZE = 256 * 1024 * 1024 ; //256 MB
|
||||
|
||||
mMaxPoolSize = MAX_POOL_SIZE ;
|
||||
if(type == STATIC_THREADED || type == VOLATILE_THREADED)
|
||||
{
|
||||
mMutexp = new LLMutex ;
|
||||
|
|
@ -1362,16 +1387,31 @@ char* LLPrivateMemoryPool::allocate(U32 size)
|
|||
chunk = chunk->mNext ;
|
||||
}
|
||||
}
|
||||
|
||||
chunk = addChunk(chunk_idx) ;
|
||||
if(chunk)
|
||||
else
|
||||
{
|
||||
p = chunk->allocate(size) ;
|
||||
chunk = addChunk(chunk_idx) ;
|
||||
if(chunk)
|
||||
{
|
||||
p = chunk->allocate(size) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unlock() ;
|
||||
|
||||
if(!p) //to get memory from the private pool failed, try the heap directly
|
||||
{
|
||||
static bool to_log = true ;
|
||||
|
||||
if(to_log)
|
||||
{
|
||||
llwarns << "The memory pool overflows, now using heap directly!" << llendl ;
|
||||
to_log = false ;
|
||||
}
|
||||
|
||||
return (char*)malloc(size) ;
|
||||
}
|
||||
|
||||
return p ;
|
||||
}
|
||||
|
||||
|
|
@ -1472,7 +1512,7 @@ void LLPrivateMemoryPool::destroyPool()
|
|||
unlock() ;
|
||||
}
|
||||
|
||||
void LLPrivateMemoryPool::checkSize(U32 asked_size)
|
||||
bool LLPrivateMemoryPool::checkSize(U32 asked_size)
|
||||
{
|
||||
if(mReservedPoolSize + asked_size > mMaxPoolSize)
|
||||
{
|
||||
|
|
@ -1480,8 +1520,12 @@ void LLPrivateMemoryPool::checkSize(U32 asked_size)
|
|||
llinfos << "Total reserved size: " << mReservedPoolSize + asked_size << llendl ;
|
||||
llinfos << "Total_allocated Size: " << getTotalAllocatedSize() << llendl ;
|
||||
|
||||
llerrs << "The pool is overflowing..." << llendl ;
|
||||
//llerrs << "The pool is overflowing..." << llendl ;
|
||||
|
||||
return false ;
|
||||
}
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_index)
|
||||
|
|
@ -1501,7 +1545,11 @@ LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_inde
|
|||
MAX_SLOT_SIZES[chunk_index], MIN_BLOCK_SIZES[chunk_index], MAX_BLOCK_SIZES[chunk_index]) ;
|
||||
}
|
||||
|
||||
checkSize(preferred_size + overhead) ;
|
||||
if(!checkSize(preferred_size + overhead))
|
||||
{
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
mReservedPoolSize += preferred_size + overhead ;
|
||||
|
||||
char* buffer = (char*)malloc(preferred_size + overhead) ;
|
||||
|
|
@ -1593,7 +1641,7 @@ LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::findChunk(const char* a
|
|||
|
||||
void LLPrivateMemoryPool::addToHashTable(LLMemoryChunk* chunk)
|
||||
{
|
||||
static const U16 HASH_FACTORS[] = {41, 83, 193, 317, 419, 523, 0xFFFF};
|
||||
static const U16 HASH_FACTORS[] = {41, 83, 193, 317, 419, 523, 719, 997, 1523, 0xFFFF};
|
||||
|
||||
U16 i ;
|
||||
if(mChunkHashList.empty())
|
||||
|
|
@ -1774,7 +1822,7 @@ void LLPrivateMemoryPool::LLChunkHashElement::remove(LLPrivateMemoryPool::LLMemo
|
|||
//--------------------------------------------------------------------
|
||||
LLPrivateMemoryPoolManager* LLPrivateMemoryPoolManager::sInstance = NULL ;
|
||||
|
||||
LLPrivateMemoryPoolManager::LLPrivateMemoryPoolManager(BOOL enabled)
|
||||
LLPrivateMemoryPoolManager::LLPrivateMemoryPoolManager(BOOL enabled, U32 max_pool_size)
|
||||
{
|
||||
mPoolList.resize(LLPrivateMemoryPool::MAX_TYPES) ;
|
||||
|
||||
|
|
@ -1784,6 +1832,9 @@ LLPrivateMemoryPoolManager::LLPrivateMemoryPoolManager(BOOL enabled)
|
|||
}
|
||||
|
||||
mPrivatePoolEnabled = enabled ;
|
||||
|
||||
const U32 MAX_POOL_SIZE = 256 * 1024 * 1024 ; //256 MB
|
||||
mMaxPrivatePoolSize = llmax(max_pool_size, MAX_POOL_SIZE) ;
|
||||
}
|
||||
|
||||
LLPrivateMemoryPoolManager::~LLPrivateMemoryPoolManager()
|
||||
|
|
@ -1826,11 +1877,11 @@ LLPrivateMemoryPoolManager::~LLPrivateMemoryPoolManager()
|
|||
}
|
||||
|
||||
//static
|
||||
void LLPrivateMemoryPoolManager::initClass(BOOL enabled)
|
||||
void LLPrivateMemoryPoolManager::initClass(BOOL enabled, U32 max_pool_size)
|
||||
{
|
||||
llassert_always(!sInstance) ;
|
||||
|
||||
sInstance = new LLPrivateMemoryPoolManager(enabled) ;
|
||||
sInstance = new LLPrivateMemoryPoolManager(enabled, max_pool_size) ;
|
||||
}
|
||||
|
||||
//static
|
||||
|
|
@ -1862,7 +1913,7 @@ LLPrivateMemoryPool* LLPrivateMemoryPoolManager::newPool(S32 type)
|
|||
|
||||
if(!mPoolList[type])
|
||||
{
|
||||
mPoolList[type] = new LLPrivateMemoryPool(type) ;
|
||||
mPoolList[type] = new LLPrivateMemoryPool(type, mMaxPrivatePoolSize) ;
|
||||
}
|
||||
|
||||
return mPoolList[type] ;
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ public:
|
|||
static void initMaxHeapSizeGB(F32 max_heap_size_gb, BOOL prevent_heap_failure);
|
||||
static void updateMemoryInfo() ;
|
||||
static void logMemoryInfo(BOOL update = FALSE);
|
||||
static S32 isMemoryPoolLow();
|
||||
static bool isMemoryPoolLow();
|
||||
|
||||
static U32 getAvailableMemKB() ;
|
||||
static U32 getMaxMemKB() ;
|
||||
|
|
@ -303,7 +303,7 @@ public:
|
|||
} ;
|
||||
|
||||
private:
|
||||
LLPrivateMemoryPool(S32 type) ;
|
||||
LLPrivateMemoryPool(S32 type, U32 max_pool_size) ;
|
||||
~LLPrivateMemoryPool() ;
|
||||
|
||||
char *allocate(U32 size) ;
|
||||
|
|
@ -320,7 +320,7 @@ private:
|
|||
void unlock() ;
|
||||
S32 getChunkIndex(U32 size) ;
|
||||
LLMemoryChunk* addChunk(S32 chunk_index) ;
|
||||
void checkSize(U32 asked_size) ;
|
||||
bool checkSize(U32 asked_size) ;
|
||||
void removeChunk(LLMemoryChunk* chunk) ;
|
||||
U16 findHashKey(const char* addr);
|
||||
void addToHashTable(LLMemoryChunk* chunk) ;
|
||||
|
|
@ -383,12 +383,12 @@ private:
|
|||
class LL_COMMON_API LLPrivateMemoryPoolManager
|
||||
{
|
||||
private:
|
||||
LLPrivateMemoryPoolManager(BOOL enabled) ;
|
||||
LLPrivateMemoryPoolManager(BOOL enabled, U32 max_pool_size) ;
|
||||
~LLPrivateMemoryPoolManager() ;
|
||||
|
||||
public:
|
||||
static LLPrivateMemoryPoolManager* getInstance() ;
|
||||
static void initClass(BOOL enabled) ;
|
||||
static void initClass(BOOL enabled, U32 pool_size) ;
|
||||
static void destroyClass() ;
|
||||
|
||||
LLPrivateMemoryPool* newPool(S32 type) ;
|
||||
|
|
@ -398,6 +398,7 @@ private:
|
|||
static LLPrivateMemoryPoolManager* sInstance ;
|
||||
std::vector<LLPrivateMemoryPool*> mPoolList ;
|
||||
BOOL mPrivatePoolEnabled;
|
||||
U32 mMaxPrivatePoolSize;
|
||||
|
||||
public:
|
||||
//debug and statistics info.
|
||||
|
|
|
|||
|
|
@ -5646,6 +5646,17 @@
|
|||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>MemoryPrivatePoolSize</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Size of the private memory pool in MB (min. value is 256)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>512</integer>
|
||||
</map>
|
||||
<key>MemProfiling</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
|
|||
|
|
@ -722,7 +722,7 @@ bool LLAppViewer::init()
|
|||
//set the max heap size.
|
||||
initMaxHeapSize() ;
|
||||
|
||||
LLPrivateMemoryPoolManager::initClass((BOOL)gSavedSettings.getBOOL("MemoryPrivatePoolEnabled")) ;
|
||||
LLPrivateMemoryPoolManager::initClass((BOOL)gSavedSettings.getBOOL("MemoryPrivatePoolEnabled"), (U32)gSavedSettings.getU32("MemoryPrivatePoolSize")) ;
|
||||
|
||||
// write Google Breakpad minidump files to our log directory
|
||||
std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
|
||||
|
|
@ -1122,9 +1122,12 @@ void LLAppViewer::checkMemory()
|
|||
{
|
||||
const static F32 MEMORY_CHECK_INTERVAL = 1.0f ; //second
|
||||
//const static F32 MAX_QUIT_WAIT_TIME = 30.0f ; //seconds
|
||||
const static U32 MAX_SIZE_CHECKED_MEMORY_BLOCK = 64 * 1024 * 1024 ; //64 MB
|
||||
//static F32 force_quit_timer = MAX_QUIT_WAIT_TIME + MEMORY_CHECK_INTERVAL ;
|
||||
static void* last_reserved_address = NULL ;
|
||||
//static F32 force_quit_timer = MAX_QUIT_WAIT_TIME + MEMORY_CHECK_INTERVAL ;
|
||||
|
||||
if(!gGLManager.mDebugGPU)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
if(MEMORY_CHECK_INTERVAL > mMemCheckTimer.getElapsedTimeF32())
|
||||
{
|
||||
|
|
@ -1132,53 +1135,12 @@ void LLAppViewer::checkMemory()
|
|||
}
|
||||
mMemCheckTimer.reset() ;
|
||||
|
||||
if(gGLManager.mDebugGPU)
|
||||
{
|
||||
//update the availability of memory
|
||||
LLMemory::updateMemoryInfo() ;
|
||||
}
|
||||
//update the availability of memory
|
||||
LLMemory::updateMemoryInfo() ;
|
||||
|
||||
//check the virtual address space fragmentation
|
||||
if(!last_reserved_address)
|
||||
{
|
||||
last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK) ;
|
||||
if(!last_reserved_address) //failed, try once more
|
||||
{
|
||||
last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK) ;
|
||||
}
|
||||
}
|
||||
bool is_low = LLMemory::isMemoryPoolLow() ;
|
||||
|
||||
S32 is_low = !last_reserved_address || LLMemory::isMemoryPoolLow() ;
|
||||
|
||||
//if(is_low < 0) //to force quit
|
||||
//{
|
||||
// if(force_quit_timer > MAX_QUIT_WAIT_TIME) //just hit the limit for the first time
|
||||
// {
|
||||
// //send out the notification to tell the viewer is about to quit in 30 seconds.
|
||||
// LLNotification::Params params("ForceQuitDueToLowMemory");
|
||||
// LLNotifications::instance().add(params);
|
||||
|
||||
// force_quit_timer = MAX_QUIT_WAIT_TIME - MEMORY_CHECK_INTERVAL ;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// force_quit_timer -= MEMORY_CHECK_INTERVAL ;
|
||||
// if(force_quit_timer < 0.f)
|
||||
// {
|
||||
// forceQuit() ; //quit
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// force_quit_timer = MAX_QUIT_WAIT_TIME + MEMORY_CHECK_INTERVAL ;
|
||||
//}
|
||||
|
||||
LLPipeline::throttleNewMemoryAllocation(!is_low ? FALSE : TRUE) ;
|
||||
LLPipeline::throttleNewMemoryAllocation(is_low) ;
|
||||
|
||||
if(is_low)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ void display_stats()
|
|||
gMemoryAllocated = LLMemory::getCurrentRSS();
|
||||
U32 memory = (U32)(gMemoryAllocated / (1024*1024));
|
||||
llinfos << llformat("MEMORY: %d MB", memory) << llendl;
|
||||
LLMemory::logMemoryInfo() ;
|
||||
LLMemory::logMemoryInfo(TRUE) ;
|
||||
gRecentMemoryTime.reset();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue