When idle the GC holds on to unused chunks indefinitely (bug 631733, r=brendan, a=blocker). (relanding in a CLOSED TREE)

This commit is contained in:
Andreas Gal 2011-02-19 22:59:49 -08:00
Родитель 04bbcc7b36
Коммит a2f58bb615
6 изменённых файлов: 23 добавлений и 15 удалений

Просмотреть файл

@ -3480,6 +3480,12 @@ DOMGCCallback(JSContext *cx, JSGCStatus status)
nsJSContext::PokeCC();
}
}
// If we didn't end up scheduling a GC, and there are unused
// chunks waiting to expire, make sure we will GC again soon.
if (!sGCTimer && JS_GetGCParameter(cx->runtime, JSGC_UNUSED_CHUNKS) > 0) {
nsJSContext::PokeGC();
}
}
JSBool result = gOldJSGCCallback ? gOldJSGCCallback(cx, status) : JS_TRUE;

Просмотреть файл

@ -2644,6 +2644,8 @@ JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key)
return rt->gcBytes;
case JSGC_MODE:
return uint32(rt->gcMode);
case JSGC_UNUSED_CHUNKS:
return uint32(rt->gcChunksWaitingToExpire);
default:
JS_ASSERT(key == JSGC_NUMBER);
return rt->gcNumber;

Просмотреть файл

@ -1785,7 +1785,10 @@ typedef enum JSGCParamKey {
JSGC_MAX_CODE_CACHE_BYTES = 6,
/* Select GC mode. */
JSGC_MODE = 7
JSGC_MODE = 7,
/* Number of GC chunks waiting to expire. */
JSGC_UNUSED_CHUNKS = 8
} JSGCParamKey;
typedef enum JSGCMode {

Просмотреть файл

@ -1047,6 +1047,7 @@ struct JSRuntime {
size_t gcLastBytes;
size_t gcMaxBytes;
size_t gcMaxMallocBytes;
size_t gcChunksWaitingToExpire;
uint32 gcEmptyArenaPoolLifespan;
uint32 gcNumber;
js::GCMarker *gcMarkingTracer;

Просмотреть файл

@ -360,14 +360,6 @@ Chunk::releaseArena(Arena<T> *arena)
info.age = 0;
}
bool
Chunk::expire()
{
if (!unused())
return false;
return info.age++ > MaxAge;
}
JSRuntime *
Chunk::getRuntime()
{
@ -456,16 +448,22 @@ PickChunk(JSRuntime *rt)
static void
ExpireGCChunks(JSRuntime *rt)
{
static const size_t MaxAge = 3;
/* Remove unused chunks. */
AutoLockGC lock(rt);
rt->gcChunksWaitingToExpire = 0;
for (GCChunkSet::Enum e(rt->gcChunkSet); !e.empty(); e.popFront()) {
Chunk *chunk = e.front();
JS_ASSERT(chunk->info.runtime == rt);
if (chunk->expire()) {
e.removeFront();
ReleaseGCChunk(rt, chunk);
continue;
if (chunk->unused()) {
if (chunk->info.age++ > MaxAge) {
e.removeFront();
ReleaseGCChunk(rt, chunk);
continue;
}
rt->gcChunksWaitingToExpire++;
}
}
}

Просмотреть файл

@ -340,7 +340,6 @@ struct Chunk {
sizeof(MarkingDelay);
static const size_t ArenasPerChunk = (GC_CHUNK_SIZE - sizeof(ChunkInfo)) / BytesPerArena;
static const size_t MaxAge = 3;
Arena<FreeCell> arenas[ArenasPerChunk];
ArenaBitmap bitmaps[ArenasPerChunk];
@ -362,7 +361,6 @@ struct Chunk {
void releaseArena(Arena<T> *a);
JSRuntime *getRuntime();
bool expire();
};
JS_STATIC_ASSERT(sizeof(Chunk) <= GC_CHUNK_SIZE);
JS_STATIC_ASSERT(sizeof(Chunk) + Chunk::BytesPerArena > GC_CHUNK_SIZE);