fix for VWR-26864: Recent commit to Snowstorm project introduces frequent errors and crashes associated with private memory pool.

master
Xiaohong Bao 2011-09-07 23:23:08 -06:00
parent 82b1b1bc6e
commit 616a7b549d
5 changed files with 102 additions and 77 deletions

View File

@ -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] ;

View File

@ -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.

View File

@ -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>

View File

@ -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)
{

View File

@ -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();
}
}