LargeObjectSpace用于保存java基礎數(shù)據(jù)類型數(shù)組或者是長字符串温算。
image.png
art虛擬機提供了兩種實現(xiàn)岗钩,要么使用LargeObjectMapSpace申眼,要么FreeListSpace谬晕。
LargeObjectMapSpace是art分配算法中最簡單的宿亡,直接匿名映射一塊內(nèi)存即可。
mirror::Object* LargeObjectMapSpace::Alloc(Thread* self, size_t num_bytes,
size_t* bytes_allocated, size_t* usable_size,
size_t* bytes_tl_bulk_allocated) {
std::string error_msg;
MemMap mem_map = MemMap::MapAnonymous("large object space allocation",
num_bytes,
PROT_READ | PROT_WRITE,
/*low_4gb=*/ true,
&error_msg);
mirror::Object* const obj = reinterpret_cast<mirror::Object*>(mem_map.Begin());
const size_t allocation_size = mem_map.BaseSize();
MutexLock mu(self, lock_);
large_objects_.Put(obj, LargeObject {std::move(mem_map), false /* not zygote */});
if (begin_ == nullptr || begin_ > reinterpret_cast<uint8_t*>(obj)) {
begin_ = reinterpret_cast<uint8_t*>(obj);
}
end_ = std::max(end_, reinterpret_cast<uint8_t*>(obj) + allocation_size);
*bytes_allocated = allocation_size;
if (usable_size != nullptr) {
*usable_size = allocation_size;
}
*bytes_tl_bulk_allocated = allocation_size;
num_bytes_allocated_ += allocation_size;
total_bytes_allocated_ += allocation_size;
++num_objects_allocated_;
++total_objects_allocated_;
return obj;
}
FreeListSpace有點類似RosAlloc彪腔。會提前分配好空間侥锦。我覺得大對象還是使用LargeObjectMapSpace好點,要使用的時候再分配
創(chuàng)建
FreeListSpace* FreeListSpace::Create(const std::string& name, size_t size) {
CHECK_EQ(size % kAlignment, 0U);
std::string error_msg;
MemMap mem_map = MemMap::MapAnonymous(name.c_str(),
size,
PROT_READ | PROT_WRITE,
/*low_4gb=*/ true,
&error_msg);
return new FreeListSpace(name, std::move(mem_map), mem_map.Begin(), mem_map.End());
}
FreeListSpace::FreeListSpace(const std::string& name,
MemMap&& mem_map,
uint8_t* begin,
uint8_t* end)
: LargeObjectSpace(name, begin, end, "free list space lock"),
mem_map_(std::move(mem_map)) {
const size_t space_capacity = end - begin;
free_end_ = space_capacity;
CHECK_ALIGNED(space_capacity, kAlignment);
const size_t alloc_info_size = sizeof(AllocationInfo) * (space_capacity / kAlignment);
std::string error_msg;
allocation_info_map_ =
MemMap::MapAnonymous("large object free list space allocation info map",
alloc_info_size,
PROT_READ | PROT_WRITE,
/*low_4gb=*/ false,
&error_msg);
CHECK(allocation_info_map_.IsValid()) << "Failed to allocate allocation info map" << error_msg;
allocation_info_ = reinterpret_cast<AllocationInfo*>(allocation_info_map_.Begin());
}
allocation_info_保存每頁的使用信息德挣。分配算法有點類似RosAlloc的Run分配恭垦,但更簡單些。從可用的空間切割出來可使用的格嗅。
mirror::Object* FreeListSpace::Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated,
size_t* usable_size, size_t* bytes_tl_bulk_allocated) {
MutexLock mu(self, lock_);
const size_t allocation_size = RoundUp(num_bytes, kAlignment);
AllocationInfo temp_info;
temp_info.SetPrevFreeBytes(allocation_size);
temp_info.SetByteSize(0, false);
AllocationInfo* new_info;
// Find the smallest chunk at least num_bytes in size.
auto it = free_blocks_.lower_bound(&temp_info);
if (it != free_blocks_.end()) {
AllocationInfo* info = *it;
free_blocks_.erase(it);
// Fit our object in the previous allocation info free space.
new_info = info->GetPrevFreeInfo();
// Remove the newly allocated block from the info and update the prev_free_.
info->SetPrevFreeBytes(info->GetPrevFreeBytes() - allocation_size);
if (info->GetPrevFreeBytes() > 0) {
AllocationInfo* new_free = info - info->GetPrevFree();
new_free->SetPrevFreeBytes(0);
new_free->SetByteSize(info->GetPrevFreeBytes(), true);
// If there is remaining space, insert back into the free set.
free_blocks_.insert(info);
}
} else {
// Try to steal some memory from the free space at the end of the space.
if (LIKELY(free_end_ >= allocation_size)) {
// Fit our object at the start of the end free block.
new_info = GetAllocationInfoForAddress(reinterpret_cast<uintptr_t>(End()) - free_end_);
free_end_ -= allocation_size;
} else {
return nullptr;
}
}
*bytes_allocated = allocation_size;
if (usable_size != nullptr) {
*usable_size = allocation_size;
}
DCHECK(bytes_tl_bulk_allocated != nullptr);
*bytes_tl_bulk_allocated = allocation_size;
// Need to do these inside of the lock.
++num_objects_allocated_;
++total_objects_allocated_;
num_bytes_allocated_ += allocation_size;
total_bytes_allocated_ += allocation_size;
mirror::Object* obj = reinterpret_cast<mirror::Object*>(GetAddressForAllocationInfo(new_info));
new_info->SetPrevFreeBytes(0);
new_info->SetByteSize(allocation_size, false);
return obj;
}
FreeListSpace適合頻繁申請然后又回收的大內(nèi)存對象的應用場景番挺。