template <class Super> void SpaceTest<Super>::SizeFootPrintGrowthLimitAndTrimBody(MallocSpace* space,
intptr_t object_size, int round,
size_t growth_limit) { if (((object_size > 0 && object_size >= static_cast<intptr_t>(growth_limit))) ||
((object_size < 0 && -object_size >= static_cast<intptr_t>(growth_limit)))) { // No allocation can succeed return;
}
// The space's footprint equals amount of resources requested from system
size_t footprint = space->GetFootprint();
// The space must at least have its book keeping allocated
EXPECT_GT(footprint, 0u);
// But it shouldn't exceed the initial size
EXPECT_LE(footprint, growth_limit);
// space's size shouldn't exceed the initial size
EXPECT_LE(space->Size(), growth_limit);
// this invariant should always hold or else the space has grown to be larger than what the // space believes its size is (which will break invariants)
EXPECT_GE(space->Size(), footprint);
// Fill the space with lots of small objects up to the growth limit
size_t max_objects = (growth_limit / (object_size > 0 ? object_size : 8)) + 1;
std::unique_ptr<mirror::Object*[]> lots_of_objects(new mirror::Object*[max_objects]);
size_t last_object = 0; // last object for which allocation succeeded
size_t amount_allocated = 0; // amount of space allocated
Thread* self = Thread::Current();
ScopedObjectAccess soa(self);
size_t rand_seed = 123456789; for (size_t i = 0; i < max_objects; i++) {
size_t alloc_fails = 0; // number of failed allocations
size_t max_fails = 30; // number of times we fail allocation before giving up for (; alloc_fails < max_fails; alloc_fails++) {
size_t alloc_size; if (object_size > 0) {
alloc_size = object_size;
} else {
alloc_size = test_rand(&rand_seed) % static_cast<size_t>(-object_size); // Note the minimum size, which is the size of a zero-length byte array.
size_t size_of_zero_length_byte_array = SizeOfZeroLengthByteArray(); if (alloc_size < size_of_zero_length_byte_array) {
alloc_size = size_of_zero_length_byte_array;
}
}
StackHandleScope<1> hs(soa.Self()); auto object(hs.NewHandle<mirror::Object>(nullptr));
size_t bytes_allocated = 0;
size_t bytes_tl_bulk_allocated; if (round <= 1) {
object.Assign(Alloc(space, self, alloc_size, &bytes_allocated, nullptr,
&bytes_tl_bulk_allocated));
} else {
object.Assign(AllocWithGrowth(space, self, alloc_size, &bytes_allocated, nullptr,
&bytes_tl_bulk_allocated));
}
footprint = space->GetFootprint();
EXPECT_GE(space->Size(), footprint); // invariant if (object != nullptr) { // allocation succeeded
lots_of_objects[i] = object.Get();
size_t allocation_size = space->AllocationSize(object.Get(), nullptr);
EXPECT_EQ(bytes_allocated, allocation_size); if (object_size > 0) {
EXPECT_GE(allocation_size, static_cast<size_t>(object_size));
} else {
EXPECT_GE(allocation_size, 8u);
}
EXPECT_TRUE(bytes_tl_bulk_allocated == 0 ||
bytes_tl_bulk_allocated >= allocation_size);
amount_allocated += allocation_size; break;
}
} if (alloc_fails == max_fails) {
last_object = i; break;
}
}
CHECK_NE(last_object, 0u); // we should have filled the space
EXPECT_GT(amount_allocated, 0u);
// We shouldn't have gone past the growth_limit
EXPECT_LE(amount_allocated, growth_limit);
EXPECT_LE(footprint, growth_limit);
EXPECT_LE(space->Size(), growth_limit);
// footprint and size should agree with amount allocated
EXPECT_GE(footprint, amount_allocated);
EXPECT_GE(space->Size(), amount_allocated);
// Release storage in a semi-adhoc manner
size_t free_increment = 96; while (true) {
{
ScopedThreadStateChange tsc(self, ThreadState::kNative); // Give the space a haircut.
space->Trim();
}
// Free some objects for (size_t i = 0; i < last_object; i += free_increment) {
mirror::Object* object = lots_of_objects.get()[i]; if (object == nullptr) { continue;
}
size_t allocation_size = space->AllocationSize(object, nullptr); if (object_size > 0) {
EXPECT_GE(allocation_size, static_cast<size_t>(object_size));
} else {
EXPECT_GE(allocation_size, 8u);
}
space->Free(self, object);
lots_of_objects.get()[i] = nullptr;
amount_allocated -= allocation_size;
footprint = space->GetFootprint();
EXPECT_GE(space->Size(), footprint); // invariant
}
free_increment >>= 1;
}
// The space has become empty here before allocating a large object // below. For RosAlloc, revoke thread-local runs, which are kept // even when empty for a performance reason, so that they won't // cause the following large object allocation to fail due to // potential fragmentation. Note they are normally revoked at each // GC (but no GC here.)
space->RevokeAllThreadLocalBuffers();
// All memory was released, try a large allocation to check freed memory is being coalesced
StackHandleScope<1> hs(soa.Self()); auto large_object(hs.NewHandle<mirror::Object>(nullptr));
size_t three_quarters_space = (growth_limit / 2) + (growth_limit / 4);
size_t bytes_allocated = 0;
size_t bytes_tl_bulk_allocated; if (round <= 1) {
large_object.Assign(Alloc(space, self, three_quarters_space, &bytes_allocated, nullptr,
&bytes_tl_bulk_allocated));
} else {
large_object.Assign(AllocWithGrowth(space, self, three_quarters_space, &bytes_allocated,
nullptr, &bytes_tl_bulk_allocated));
}
EXPECT_TRUE(large_object != nullptr);
// Consistency check of the footprint.
footprint = space->GetFootprint();
EXPECT_LE(footprint, growth_limit);
EXPECT_GE(space->Size(), footprint);
EXPECT_LE(space->Size(), growth_limit);
// Make space findable to the heap, will also delete space when runtime is cleaned up
AddSpace(space);
// In this round we don't allocate with growth and therefore can't grow past the initial size. // This effectively makes the growth_limit the initial_size, so assert this.
SizeFootPrintGrowthLimitAndTrimBody(space, object_size, 1, initial_size);
SizeFootPrintGrowthLimitAndTrimBody(space, object_size, 2, growth_limit); // Remove growth limit
space->ClearGrowthLimit();
EXPECT_EQ(space->Capacity(), capacity);
SizeFootPrintGrowthLimitAndTrimBody(space, object_size, 3, capacity);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.