linker: Purge block allocator memory when possible

If all allocated memory from a block allocator is freed, it is a good
opportunity to purge all the pages allocated to reduce lingering dirty
pages.

Memory saving varies with the platform and what processes are running.
Measuring right after boot, this saves ~1.8MB on cuttelfish and ~1.3MB
on a 32-bit ARM device.

Bug: 112073665
Test: Boot and check memory usage with 'showmap'.
Change-Id: I53769e0ec9699f0b3645cdf281a2c0bbffb98676
This commit is contained in:
Vic Yang 2019-01-23 12:19:41 -08:00
parent 176d2fbcae
commit fb78a4ac1b
2 changed files with 28 additions and 2 deletions

View File

@ -52,7 +52,8 @@ LinkerBlockAllocator::LinkerBlockAllocator(size_t block_size)
: block_size_(
round_up(block_size < sizeof(FreeBlockInfo) ? sizeof(FreeBlockInfo) : block_size, 16)),
page_list_(nullptr),
free_block_list_(nullptr)
free_block_list_(nullptr),
allocated_(0)
{}
void* LinkerBlockAllocator::alloc() {
@ -73,6 +74,8 @@ void* LinkerBlockAllocator::alloc() {
memset(block_info, 0, block_size_);
++allocated_;
return block_info;
}
@ -101,6 +104,11 @@ void LinkerBlockAllocator::free(void* block) {
block_info->num_free_blocks = 1;
free_block_list_ = block_info;
--allocated_;
if (allocated_ == 0) {
free_all_pages();
}
}
void LinkerBlockAllocator::protect_all(int prot) {
@ -151,3 +159,18 @@ LinkerBlockAllocatorPage* LinkerBlockAllocator::find_page(void* block) {
abort();
}
void LinkerBlockAllocator::free_all_pages() {
if (allocated_) {
abort();
}
LinkerBlockAllocatorPage* page = page_list_;
while (page) {
LinkerBlockAllocatorPage* next = page->next;
munmap(page, PAGE_SIZE);
page = next;
}
page_list_ = nullptr;
free_block_list_ = nullptr;
}

View File

@ -53,10 +53,12 @@ class LinkerBlockAllocator {
private:
void create_new_page();
LinkerBlockAllocatorPage* find_page(void* block);
void free_all_pages();
size_t block_size_;
LinkerBlockAllocatorPage* page_list_;
void* free_block_list_;
size_t allocated_;
DISALLOW_COPY_AND_ASSIGN(LinkerBlockAllocator);
};
@ -73,7 +75,8 @@ class LinkerBlockAllocator {
* with size 513 this allocator will use 516 (520 for lp64) bytes of data
* where generalized implementation is going to use 1024 sized blocks.
*
* 2. This allocator does not munmap allocated memory, where LinkerMemoryAllocator does.
* 2. Unless all allocated memory is freed, this allocator does not munmap
* allocated memory, where LinkerMemoryAllocator does.
*
* 3. This allocator provides mprotect services to the user, where LinkerMemoryAllocator
* always treats it's memory as READ|WRITE.