forked from mirrors/0ad
Modify GC scheduling and reduce VFS cache size.
It seems like there is a memory leak if we haven't finished with the marking phase of an incremental GC and SpiderMonkey has to trigger a full GC because it runs out of memory. With this patch we stop trying to make incremental GCs if we are above 1/2 of the runtime size and do Full GCs instead. This should make such low memory conditions even less likely than they were already after the previous patch. Also reduce the maximum VFS cache size to 400 MB. Refs #2808 This was SVN commit r15831.
This commit is contained in:
@@ -358,7 +358,7 @@ static size_t ChooseCacheSize()
|
||||
const ssize_t os = (ssize_t)OperatingSystemFootprint();
|
||||
const ssize_t game = 300; // estimated working set
|
||||
|
||||
ssize_t cache = 500; // upper bound: total size of our data
|
||||
ssize_t cache = 400; // upper bound: total size of our data
|
||||
|
||||
// the cache reserves contiguous address space, which is a precious
|
||||
// resource on 32-bit systems, so don't use too much:
|
||||
|
||||
@@ -139,7 +139,8 @@ public:
|
||||
m_rooter(NULL),
|
||||
m_LastGCBytes(0),
|
||||
m_LastGCCheck(0.0f),
|
||||
m_HeapGrowthBytesGCTrigger(heapGrowthBytesGCTrigger)
|
||||
m_HeapGrowthBytesGCTrigger(heapGrowthBytesGCTrigger),
|
||||
m_RuntimeSize(runtimeSize)
|
||||
{
|
||||
m_rt = JS_NewRuntime(runtimeSize, JS_USE_HELPER_THREADS);
|
||||
|
||||
@@ -161,11 +162,9 @@ public:
|
||||
|
||||
JS::SetGCSliceCallback(m_rt, GCSliceCallbackHook);
|
||||
|
||||
JS_SetGCParameter(m_rt, JSGC_MAX_MALLOC_BYTES, 384 * 1024 * 1024);
|
||||
JS_SetGCParameter(m_rt, JSGC_MAX_BYTES, 384 * 1024 * 1024);
|
||||
JS_SetGCParameter(m_rt, JSGC_MAX_MALLOC_BYTES, m_RuntimeSize);
|
||||
JS_SetGCParameter(m_rt, JSGC_MAX_BYTES, m_RuntimeSize);
|
||||
JS_SetGCParameter(m_rt, JSGC_MODE, JSGC_MODE_INCREMENTAL);
|
||||
//JS_SetGCParameter(m_rt, JSGC_SLICE_TIME_BUDGET, 5);
|
||||
JS_SetGCParameter(m_rt, JSGC_ALLOCATION_THRESHOLD, 256);
|
||||
|
||||
// The whole heap-growth mechanism seems to work only for non-incremental GCs.
|
||||
// We disable it to make it more clear if full GCs happen triggered by this JSAPI internal mechanism.
|
||||
@@ -177,6 +176,7 @@ public:
|
||||
ENSURE(m_dummyContext);
|
||||
}
|
||||
|
||||
#define GC_DEBUG_PRINT 0
|
||||
void MaybeIncrementalGC(double delay)
|
||||
{
|
||||
PROFILE2("MaybeIncrementalGC");
|
||||
@@ -201,30 +201,66 @@ public:
|
||||
m_LastGCCheck = timer_Time();
|
||||
|
||||
int gcBytes = JS_GetGCParameter(m_rt, JSGC_BYTES);
|
||||
//std::cout << "gcBytes: " << std::endl; // debugging
|
||||
|
||||
#if GC_DEBUG_PRINT
|
||||
std::cout << "gcBytes: " << gcBytes / 1024 << " KB" << std::endl;
|
||||
#endif
|
||||
|
||||
if (m_LastGCBytes > gcBytes || m_LastGCBytes == 0)
|
||||
{
|
||||
//printf("Setting m_LastGCBytes: %d \n", gcBytes); // debugging
|
||||
#if GC_DEBUG_PRINT
|
||||
printf("Setting m_LastGCBytes: %d KB \n", gcBytes / 1024);
|
||||
#endif
|
||||
m_LastGCBytes = gcBytes;
|
||||
}
|
||||
|
||||
|
||||
// Run an additional incremental GC slice if the currently running incremental GC isn't over yet
|
||||
// ... or
|
||||
// start a new incremental GC if the JS heap size has grown enough for a GC to make sense
|
||||
if (JS::IsIncrementalGCInProgress(m_rt) || (gcBytes - m_LastGCBytes > m_HeapGrowthBytesGCTrigger))
|
||||
{
|
||||
// Use for debugging
|
||||
/*if (JS::IsIncrementalGCInProgress(m_rt))
|
||||
printf("Running incremental GC because an incremental cycle is in progress. \n");
|
||||
{
|
||||
#if GC_DEBUG_PRINT
|
||||
if (JS::IsIncrementalGCInProgress(m_rt))
|
||||
printf("An incremental GC cycle is in progress. \n");
|
||||
else
|
||||
printf("Running incremental GC because JSGC_BYTES - m_LastGCBytes > m_HeapGrowthBytesGCTrigger "
|
||||
" ---- JSGC_BYTES: %d m_LastGCBytes: %d m_HeapGrowthBytesGCTrigger: %d ",
|
||||
gcBytes,
|
||||
m_LastGCBytes,
|
||||
m_HeapGrowthBytesGCTrigger);
|
||||
}*/
|
||||
PrepareContextsForIncrementalGC();
|
||||
JS::IncrementalGC(m_rt, JS::gcreason::REFRESH_FRAME, GCSliceTimeBudget);
|
||||
printf("GC needed because JSGC_BYTES - m_LastGCBytes > m_HeapGrowthBytesGCTrigger \n"
|
||||
" JSGC_BYTES: %d KB \n m_LastGCBytes: %d KB \n m_HeapGrowthBytesGCTrigger: %d KB \n",
|
||||
gcBytes / 1024,
|
||||
m_LastGCBytes / 1024,
|
||||
m_HeapGrowthBytesGCTrigger / 1024);
|
||||
#endif
|
||||
|
||||
// A hack to make sure we never exceed the runtime size because we can't collect the memory
|
||||
// fast enough.
|
||||
if(gcBytes > m_RuntimeSize / 2)
|
||||
{
|
||||
if (JS::IsIncrementalGCInProgress(m_rt))
|
||||
{
|
||||
#if GC_DEBUG_PRINT
|
||||
printf("Finishing incremental GC because gcBytes > m_RuntimeSize / 2. \n");
|
||||
#endif
|
||||
PrepareContextsForIncrementalGC();
|
||||
JS::FinishIncrementalGC(m_rt, JS::gcreason::REFRESH_FRAME);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if GC_DEBUG_PRINT
|
||||
printf("Running full GC because gcBytes > m_RuntimeSize / 2. \n");
|
||||
#endif
|
||||
JS_GC(m_rt);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if GC_DEBUG_PRINT
|
||||
if (!JS::IsIncrementalGCInProgress(m_rt))
|
||||
printf("Starting incremental GC \n");
|
||||
else
|
||||
printf("Running incremental GC slice \n");
|
||||
#endif
|
||||
PrepareContextsForIncrementalGC();
|
||||
JS::IncrementalGC(m_rt, JS::gcreason::REFRESH_FRAME, GCSliceTimeBudget);
|
||||
}
|
||||
m_LastGCBytes = gcBytes;
|
||||
}
|
||||
}
|
||||
@@ -255,6 +291,7 @@ private:
|
||||
// Workaround for: https://bugzilla.mozilla.org/show_bug.cgi?id=890243
|
||||
JSContext* m_dummyContext;
|
||||
|
||||
int m_RuntimeSize;
|
||||
int m_HeapGrowthBytesGCTrigger;
|
||||
int m_LastGCBytes;
|
||||
double m_LastGCCheck;
|
||||
|
||||
Reference in New Issue
Block a user