aboutsummaryrefslogtreecommitdiffstats
path: root/linker
diff options
context:
space:
mode:
authorVic Yang <victoryang@google.com>2019-01-23 12:19:41 -0800
committerVic Yang <victoryang@google.com>2019-01-23 12:24:46 -0800
commitfb78a4ac1b93218f59aa44089ae5f4dbfababf0d (patch)
tree976bf1fa16427ea8a3bce0cbc6cb29cd94390449 /linker
parent176d2fbcaefe4691b8fd7844f6cec8e7a1a22c76 (diff)
downloadandroid_bionic-fb78a4ac1b93218f59aa44089ae5f4dbfababf0d.tar.gz
android_bionic-fb78a4ac1b93218f59aa44089ae5f4dbfababf0d.tar.bz2
android_bionic-fb78a4ac1b93218f59aa44089ae5f4dbfababf0d.zip
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
Diffstat (limited to 'linker')
-rw-r--r--linker/linker_block_allocator.cpp25
-rw-r--r--linker/linker_block_allocator.h5
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.