From fb78a4ac1b93218f59aa44089ae5f4dbfababf0d Mon Sep 17 00:00:00 2001 From: Vic Yang Date: Wed, 23 Jan 2019 12:19:41 -0800 Subject: [PATCH] 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 --- linker/linker_block_allocator.cpp | 25 ++++++++++++++++++++++++- linker/linker_block_allocator.h | 5 ++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/linker/linker_block_allocator.cpp b/linker/linker_block_allocator.cpp index dca944e9c..34df9a5d8 100644 --- a/linker/linker_block_allocator.cpp +++ b/linker/linker_block_allocator.cpp @@ -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; +} diff --git a/linker/linker_block_allocator.h b/linker/linker_block_allocator.h index bd44fc829..85e6bd962 100644 --- a/linker/linker_block_allocator.h +++ b/linker/linker_block_allocator.h @@ -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.