force major collection under low memory condition

This commit is contained in:
Joel Dice 2008-01-14 09:39:57 -07:00
parent 029973943e
commit a89c22b493
3 changed files with 77 additions and 42 deletions

View File

@ -17,7 +17,11 @@ const unsigned Top = ~static_cast<unsigned>(0);
const unsigned InitialGen2CapacityInBytes = 4 * 1024 * 1024; const unsigned InitialGen2CapacityInBytes = 4 * 1024 * 1024;
const unsigned InitialTenuredFixieCeilingInBytes = 4 * 1024 * 1024; const unsigned InitialTenuredFixieCeilingInBytes = 4 * 1024 * 1024;
const unsigned MajorCollectionInterval = 16; // do a major collection at least every N collections (zero means
// infinity)
const unsigned MajorCollectionInterval = 0;
const unsigned LowMemoryPaddingInBytes = 1024 * 1024;
const bool Verbose = false; const bool Verbose = false;
const bool Verbose2 = false; const bool Verbose2 = false;
@ -306,8 +310,7 @@ class Segment {
while (data == 0) { while (data == 0) {
data = static_cast<uintptr_t*> data = static_cast<uintptr_t*>
(tryAllocate (tryAllocate
(context, 0, (capacity_ + mapFootprint(capacity_)) * BytesPerWord, (context, 0, (footprint(capacity_)) * BytesPerWord, false));
false));
if (data == 0) { if (data == 0) {
if (capacity_ > minimum) { if (capacity_ > minimum) {
@ -327,8 +330,8 @@ class Segment {
} }
} }
unsigned mapFootprint(unsigned capacity) { unsigned footprint(unsigned capacity) {
return map and capacity ? map->footprint(capacity) : 0; return capacity + (map and capacity ? map->footprint(capacity) : 0);
} }
unsigned capacity() { unsigned capacity() {
@ -345,8 +348,7 @@ class Segment {
void replaceWith(Segment* s) { void replaceWith(Segment* s) {
if (data) { if (data) {
free(context, data, free(context, data, (footprint(capacity())) * BytesPerWord, false);
(capacity() + mapFootprint(capacity())) * BytesPerWord, false);
} }
data = s->data; data = s->data;
s->data = 0; s->data = 0;
@ -397,8 +399,7 @@ class Segment {
} }
void dispose() { void dispose() {
free(context, data, free(context, data, (footprint(capacity())) * BytesPerWord, false);
(capacity() + mapFootprint(capacity())) * BytesPerWord, false);
data = 0; data = 0;
map = 0; map = 0;
} }
@ -515,9 +516,11 @@ class Context {
nextGen2(this, &nextHeapMap, 0, 0), nextGen2(this, &nextHeapMap, 0, 0),
gen2Base(0), gen2Base(0),
incomingFootprint(0),
tenureFootprint(0), tenureFootprint(0),
gen1padding(0), gen1Padding(0),
gen2padding(0), tenurePadding(0),
gen2Padding(0),
fixieTenureFootprint(0), fixieTenureFootprint(0),
untenuredFixieFootprint(0), untenuredFixieFootprint(0),
@ -583,9 +586,11 @@ class Context {
unsigned gen2Base; unsigned gen2Base;
unsigned incomingFootprint;
unsigned tenureFootprint; unsigned tenureFootprint;
unsigned gen1padding; unsigned gen1Padding;
unsigned gen2padding; unsigned tenurePadding;
unsigned gen2Padding;
unsigned fixieTenureFootprint; unsigned fixieTenureFootprint;
unsigned untenuredFixieFootprint; unsigned untenuredFixieFootprint;
@ -643,14 +648,43 @@ assert(Context* c, bool v)
} }
#endif #endif
inline unsigned
minimumNextGen1Capacity(Context* c)
{
return c->gen1.position() - c->tenureFootprint + c->incomingFootprint
+ c->gen1Padding;
}
inline unsigned
minimumNextGen2Capacity(Context* c)
{
return c->gen2.position() + c->tenureFootprint + c->tenurePadding
+ c->gen2Padding;
}
inline bool
oversizedGen2(Context* c)
{
return c->gen2.capacity() > (InitialGen2CapacityInBytes / BytesPerWord)
and c->gen2.position() < (c->gen2.capacity() / 4);
}
inline bool
lowMemory(Context* c)
{
return ((c->gen1.footprint(minimumNextGen1Capacity(c))
+ c->gen2.footprint(minimumNextGen2Capacity(c))) * BytesPerWord)
+ LowMemoryPaddingInBytes
> c->limit - c->count;
}
inline void inline void
initNextGen1(Context* c, unsigned footprint) initNextGen1(Context* c)
{ {
new (&(c->nextAgeMap)) Segment::Map new (&(c->nextAgeMap)) Segment::Map
(&(c->nextGen1), max(1, log(TenureThreshold)), 1, 0, false); (&(c->nextGen1), max(1, log(TenureThreshold)), 1, 0, false);
unsigned minimum unsigned minimum = minimumNextGen1Capacity(c);
= (c->gen1.position() - c->tenureFootprint) + footprint + c->gen1padding;
unsigned desired = minimum; unsigned desired = minimum;
new (&(c->nextGen1)) Segment(c, &(c->nextAgeMap), desired, minimum); new (&(c->nextGen1)) Segment(c, &(c->nextAgeMap), desired, minimum);
@ -661,13 +695,6 @@ initNextGen1(Context* c, unsigned footprint)
} }
} }
inline bool
oversizedGen2(Context* c)
{
return c->gen2.capacity() > (InitialGen2CapacityInBytes / BytesPerWord)
and c->gen2.position() < (c->gen2.capacity() / 4);
}
inline void inline void
initNextGen2(Context* c) initNextGen2(Context* c)
{ {
@ -681,10 +708,10 @@ initNextGen2(Context* c)
new (&(c->nextHeapMap)) Segment::Map new (&(c->nextHeapMap)) Segment::Map
(&(c->nextGen2), 1, c->pageMap.scale * 1024, &(c->nextPageMap), true); (&(c->nextGen2), 1, c->pageMap.scale * 1024, &(c->nextPageMap), true);
unsigned minimum = c->gen2.position() + c->tenureFootprint + c->gen2padding; unsigned minimum = minimumNextGen2Capacity(c);
unsigned desired = minimum; unsigned desired = minimum;
if (not oversizedGen2(c)) { if (not (lowMemory(c) or oversizedGen2(c))) {
desired *= 2; desired *= 2;
} }
@ -1451,8 +1478,12 @@ collect2(Context* c)
c->gen2Base = Top; c->gen2Base = Top;
c->tenureFootprint = 0; c->tenureFootprint = 0;
c->fixieTenureFootprint = 0; c->fixieTenureFootprint = 0;
c->gen1padding = 0; c->gen1Padding = 0;
c->gen2padding = 0; c->tenurePadding = 0;
if (c->mode == Heap::MajorCollection) {
c->gen2Padding = 0;
}
if (c->mode == Heap::MinorCollection and c->gen2.position()) { if (c->mode == Heap::MinorCollection and c->gen2.position()) {
unsigned start = 0; unsigned start = 0;
@ -1481,17 +1512,20 @@ collect2(Context* c)
} }
void void
collect(Context* c, unsigned footprint) collect(Context* c)
{ {
if (oversizedGen2(c) if (lowMemory(c)
or c->tenureFootprint + c->gen2padding > c->gen2.remaining() or oversizedGen2(c)
or c->tenureFootprint + c->tenurePadding > c->gen2.remaining()
or c->fixieTenureFootprint + c->tenuredFixieFootprint or c->fixieTenureFootprint + c->tenuredFixieFootprint
> c->tenuredFixieCeiling) > c->tenuredFixieCeiling)
{ {
if (Verbose) { if (Verbose) {
if (oversizedGen2(c)) { if (lowMemory(c)) {
fprintf(stderr, "low memory causes ");
} else if (oversizedGen2(c)) {
fprintf(stderr, "oversized gen2 causes "); fprintf(stderr, "oversized gen2 causes ");
} else if (c->tenureFootprint + c->gen2padding > c->gen2.remaining()) } else if (c->tenureFootprint + c->tenurePadding > c->gen2.remaining())
{ {
fprintf(stderr, "undersized gen2 causes "); fprintf(stderr, "undersized gen2 causes ");
} else { } else {
@ -1524,7 +1558,7 @@ collect(Context* c, unsigned footprint)
then = c->system->now(); then = c->system->now();
} }
initNextGen1(c, footprint); initNextGen1(c);
if (c->mode == Heap::MajorCollection) { if (c->mode == Heap::MajorCollection) {
c->majorCollectionCountdown = MajorCollectionInterval; c->majorCollectionCountdown = MajorCollectionInterval;
@ -1636,10 +1670,11 @@ class MyHeap: public Heap {
free_(&c, p, size, executable); free_(&c, p, size, executable);
} }
virtual void collect(CollectionType type, unsigned footprint) { virtual void collect(CollectionType type, unsigned incomingFootprint) {
c.mode = type; c.mode = type;
c.incomingFootprint = incomingFootprint;
::collect(&c, footprint); ::collect(&c);
} }
virtual void* allocateFixed(Allocator* allocator, void* clientContext, virtual void* allocateFixed(Allocator* allocator, void* clientContext,
@ -1705,17 +1740,17 @@ class MyHeap: public Heap {
} }
} }
virtual void pad(void* p, unsigned extra) { virtual void pad(void* p) {
if (c.gen1.contains(p)) { if (c.gen1.contains(p)) {
if (c.ageMap.get(p) == TenureThreshold) { if (c.ageMap.get(p) == TenureThreshold) {
c.gen2padding += extra; ++ c.tenurePadding;
} else { } else {
c.gen1padding += extra; ++ c.gen1Padding;
} }
} else if (c.gen2.contains(p)) { } else if (c.gen2.contains(p)) {
c.gen2padding += extra; ++ c.gen2Padding;
} else { } else {
c.gen1padding += extra; ++ c.gen1Padding;
} }
} }

View File

@ -55,7 +55,7 @@ class Heap: public Allocator {
bool objectMask, unsigned* totalInBytes) = 0; bool objectMask, unsigned* totalInBytes) = 0;
virtual bool needsMark(void* p) = 0; virtual bool needsMark(void* p) = 0;
virtual void mark(void* p, unsigned offset, unsigned count) = 0; virtual void mark(void* p, unsigned offset, unsigned count) = 0;
virtual void pad(void* p, unsigned extra) = 0; virtual void pad(void* p) = 0;
virtual void* follow(void* p) = 0; virtual void* follow(void* p) = 0;
virtual Status status(void* p) = 0; virtual Status status(void* p) = 0;
virtual CollectionType collectionType() = 0; virtual CollectionType collectionType() = 0;

View File

@ -1719,7 +1719,7 @@ markHashTaken(Thread* t, object o)
ACQUIRE_RAW(t, t->m->heapLock); ACQUIRE_RAW(t, t->m->heapLock);
cast<uintptr_t>(o, 0) |= HashTakenMark; cast<uintptr_t>(o, 0) |= HashTakenMark;
t->m->heap->pad(o, 1); t->m->heap->pad(o);
} }
inline uint32_t inline uint32_t