summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy McFadden <fadden@android.com>2011-11-04 12:56:55 -0700
committerAndy McFadden <fadden@android.com>2011-11-04 13:06:04 -0700
commitaf6cf54652d1b27885b99e216bee29b955052630 (patch)
tree914acd163e35c069034aae38f01759fd7681c7c2
parentab97cd1634ed4e2c9e5c558a9f88ed9ca8623c8c (diff)
downloadandroid_dalvik-af6cf54652d1b27885b99e216bee29b955052630.tar.gz
android_dalvik-af6cf54652d1b27885b99e216bee29b955052630.tar.bz2
android_dalvik-af6cf54652d1b27885b99e216bee29b955052630.zip
Reduce Dalvik card table overhead
The VM has a "growth limit" (e.g. 48MB) that is used to cap normal apps, and a "max heap" (e.g. 128MB) that is used for apps with unusual high-memory requirements. The Dalvik GC uses a 128:1 "card table" that spans the entire managed heap, out to the "max heap" limit. The table is erased during every concurrent GC. The first time we do that post-zygote, the copy-on-write behavior causes physical pages to be allocated. We're currently clearing out to the heap max, not the growth limit, which means we have a bunch of physical memory allocated for pages that will never be used. This changes it so we only clear out to the growth limit. If the growth limit is removed by the app, we clear out to the heap max. On devices with a 128MB max heap, this reduces the private/dirty usage for most apps by 640KB. Bug 5567332 Change-Id: Iac633017c128d63b284d48016e47d40cc46df1de
-rw-r--r--vm/alloc/CardTable.cpp23
-rw-r--r--vm/alloc/CardTable.h2
-rw-r--r--vm/alloc/Heap.cpp2
-rw-r--r--vm/alloc/HeapInternal.h1
-rw-r--r--vm/alloc/HeapSource.cpp1
5 files changed, 25 insertions, 4 deletions
diff --git a/vm/alloc/CardTable.cpp b/vm/alloc/CardTable.cpp
index c24be0187..212c9d015 100644
--- a/vm/alloc/CardTable.cpp
+++ b/vm/alloc/CardTable.cpp
@@ -48,7 +48,7 @@
* Initializes the card table; must be called before any other
* dvmCardTable*() functions.
*/
-bool dvmCardTableStartup(size_t heapMaximumSize)
+bool dvmCardTableStartup(size_t heapMaximumSize, size_t growthLimit)
{
size_t length;
void *allocBase;
@@ -67,7 +67,8 @@ bool dvmCardTableStartup(size_t heapMaximumSize)
return false;
}
gcHeap->cardTableBase = (u1*)allocBase;
- gcHeap->cardTableLength = length;
+ gcHeap->cardTableLength = growthLimit / GC_CARD_SIZE;
+ gcHeap->cardTableMaxLength = length;
gcHeap->cardTableOffset = 0;
/* All zeros is the correct initial value; all clean. */
assert(GC_CARD_CLEAN == 0);
@@ -96,8 +97,26 @@ void dvmCardTableShutdown()
void dvmClearCardTable()
{
+ /*
+ * The goal is to zero out some mmap-allocated pages. We can accomplish
+ * this with memset() or madvise(MADV_DONTNEED). The latter has some
+ * useful properties, notably that the pages are returned to the system,
+ * so cards for parts of the heap we haven't expanded into won't be
+ * allocated physical pages. On the other hand, if we un-map the card
+ * area, we'll have to fault it back in as we resume dirtying objects,
+ * which reduces performance. (Also, "the kernel is free to ignore the
+ * advice" makes this sound like something we can't necessarily rely on
+ * to synchronously clear memory; may need to memset *and* madvise.)
+ *
+ * TODO: use memset() to clear out to the current "soft" limit, and
+ * madvise() to clear out the rest.
+ *
+ * Note that cardTableLength is initially set to the growth limit, and
+ * on request will be expanded to the heap maximum.
+ */
assert(gDvm.gcHeap->cardTableBase != NULL);
memset(gDvm.gcHeap->cardTableBase, GC_CARD_CLEAN, gDvm.gcHeap->cardTableLength);
+ //madvise(gDvm.gcHeap->cardTableBase, gDvm.gcHeap->cardTableLength, MADV_DONTNEED);
}
/*
diff --git a/vm/alloc/CardTable.h b/vm/alloc/CardTable.h
index 532c25963..43b0563b1 100644
--- a/vm/alloc/CardTable.h
+++ b/vm/alloc/CardTable.h
@@ -32,7 +32,7 @@
* Initializes the card table; must be called before any other
* dvmCardTable*() functions.
*/
-bool dvmCardTableStartup(size_t heapMaximumSize);
+bool dvmCardTableStartup(size_t heapMaximumSize, size_t growthLimit);
/*
* Tears down the entire CardTable structure.
diff --git a/vm/alloc/Heap.cpp b/vm/alloc/Heap.cpp
index db640a6c1..9eee817e5 100644
--- a/vm/alloc/Heap.cpp
+++ b/vm/alloc/Heap.cpp
@@ -97,7 +97,7 @@ bool dvmHeapStartup()
*/
gcHeap->clearedReferences = NULL;
- if (!dvmCardTableStartup(gDvm.heapMaximumSize)) {
+ if (!dvmCardTableStartup(gDvm.heapMaximumSize, gDvm.heapGrowthLimit)) {
LOGE_HEAP("card table startup failed.");
return false;
}
diff --git a/vm/alloc/HeapInternal.h b/vm/alloc/HeapInternal.h
index a893bb259..185af1cb9 100644
--- a/vm/alloc/HeapInternal.h
+++ b/vm/alloc/HeapInternal.h
@@ -48,6 +48,7 @@ struct GcHeap {
/* GC's card table */
u1* cardTableBase;
size_t cardTableLength;
+ size_t cardTableMaxLength;
size_t cardTableOffset;
/* Is the GC running? Used to avoid recursive calls to GC.
diff --git a/vm/alloc/HeapSource.cpp b/vm/alloc/HeapSource.cpp
index d3779d8f9..f61724a40 100644
--- a/vm/alloc/HeapSource.cpp
+++ b/vm/alloc/HeapSource.cpp
@@ -1069,6 +1069,7 @@ void dvmClearGrowthLimit()
HS_BOILERPLATE();
dvmLockHeap();
dvmWaitForConcurrentGcToComplete();
+ gDvm.gcHeap->cardTableLength = gDvm.gcHeap->cardTableMaxLength;
gHs->growthLimit = gHs->maximumSize;
size_t overhead = oldHeapOverhead(gHs, false);
gHs->heaps[0].maximumSize = gHs->maximumSize - overhead;